/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.repair.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springblade.common.cache.DictCache;
import org.springblade.common.config.BladeOssRuleExt;
import org.springblade.common.constant.TemplateMsgConstant;
import org.springblade.common.utils.AsyncHttpUtil;
import org.springblade.common.utils.RobotUtil;
import org.springblade.common.utils.mq.NormalSend;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseEntity;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.node.ForestNodeMerger;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.repair.dto.*;
import org.springblade.modules.repair.dto.plan.PlanOrderHomePage4SearchDTO;
import org.springblade.modules.repair.dto.plan.offline.ByPlanOfflineDetailDTO;
import org.springblade.modules.repair.dto.plan.PlanOrderHomePageSearchDTO;
import org.springblade.modules.repair.dto.statistical.by.CheckStatisticsPlanSimpleDTO;
import org.springblade.modules.repair.entity.*;
import org.springblade.modules.repair.enums.*;
import org.springblade.modules.repair.mapper.MaintainPlanContentMapper;
import org.springblade.modules.repair.service.*;
import org.springblade.modules.repair.utils.DateUtils;
import org.springblade.modules.repair.utils.DistanceUtils;
import org.springblade.modules.repair.utils.WatermarkImgUtils;
import org.springblade.modules.repair.vo.*;
import org.springblade.modules.repair.vo.defert.PlanConfigVo;
import org.springblade.modules.repair.vo.elevator.ElevatorPartWorkVo;
import org.springblade.modules.repair.vo.plan.*;
import org.springblade.modules.repair.vo.plan.PlanDetailVo;
import org.springblade.modules.repair.vo.plan.statistics.WxBuildingSimpleVO;
import org.springblade.modules.repair.vo.plan.statistics.WxElevatorSimpleVO;
import org.springblade.modules.repair.vo.plan.store.ByWorkScoreInfoVo;
import org.springblade.modules.repair.vo.plan.v2.*;
import org.springblade.modules.resource.builder.oss.OssBuilder;
import org.springblade.modules.system.entity.Dict;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.service.IDeptService;
import org.springblade.modules.system.service.IDictService;
import org.springblade.modules.system.service.IUserService;
import org.springblade.modules.system.vo.SimpleUserVO;
import org.springblade.modules.system.vo.UserVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 维保任务表 服务实现类
 *
 * @author ysq
 * @since 2022-03-28
 */
@Service
@Slf4j
public class MaintainPlanContentServiceImpl extends BaseServiceImpl<MaintainPlanContentMapper, MaintainPlanContent> implements IMaintainPlanContentService {

	@Autowired
	private BuildingContactsService buildingContactsService;
	@Autowired
	private IElevatorService elevatorService;
	@Autowired
	private MaintainTemplateService templateService;
	@Autowired
	private IMaintainPlanTemplateService planTemplateService;
	@Autowired
	private IMaintainCheckHistoryService checkHistoryService;
	@Autowired
	private IMaintainMalfunctionLogService malfunctionLogService;
	@Autowired
	@Lazy
	private IMaintainSignService signService;
	@Autowired
	private IMaintainPlanContentExtService maintainPlanContentExtService;
	@Autowired
	private MaintainTemplateLocationTypeService templateLocationTypeService;
	@Autowired
	private IMaintainPlanContentUserService planContentUserService;
	@Autowired
	@Lazy
	private IUserService userService;
	@Autowired
	@Lazy
	private MaintainSigntureService signtureService;
	@Autowired
	private NormalSend normalSend;
	@Autowired
	private IDictService dictService;
	@Autowired
	@Lazy
	private IDeptService deptService;
	@Autowired
	private MaintainPlanConfigService maintainPlanConfigService;
	@Autowired
	private AsyncHttpUtil asyncHttpUtil;
	@Autowired
	private OssBuilder ossBuilder;
	@Autowired
	private RobotUtil robotUtil;
	@Autowired
	@Lazy
	private IMaintainMalfunctionRescueService maintainMalfunctionRescueService;
	@Autowired
	@Lazy
	private IMaintainMalfunctionWorkService maintainMalfunctionWorkService;
	@Autowired
	@Lazy
	private MaintainPartsWorkService maintainPartsWorkService;
	@Autowired
	private MaintainCheckRecordService checkRecordService;
	@Autowired
	private MaintainPlanContentOfflineService planContentOfflineService;

	@Autowired
	@Lazy
	private IMaintainPlanAffairService maintainPlanAffairService;
	@Autowired
	@Lazy
	private IMaintainPlanCheckService maintainPlanCheckService;
	@Autowired
	private IMaintainPlanTemplateService maintainPlanTemplateService;
	@Autowired
	private IMaintainTemplateRelationService templateRelationService;

	@Autowired
	@Lazy
	private IPlanCheckHistoryScoreService planCheckHistoryScoreService;
	@Lazy
	@Autowired
	private PlanHistoryImageService planHistoryImageService;
	@Autowired
	private ElevatorPlanStrategyService elevatorPlanStrategyService;

	@Autowired
	private IWxFaultCauseService wxFaultCauseService;

	@Value("${project.api.url.estate}")
	private String estateApiUrl;
	@Value("${project.api.url.web}")
	private String maintainApiUrl;
	private final String note_push_url = "/tlw/alarm/note/push";
	private final String official_accounts_push_url = "/tlw/alarm/official/accounts/push";
	private final String estate_sms_code = "twy_estate_sign_push";

	//表示梯无忧内部调用物业端模板消息
	private final Integer sendType = 1;

	/**
	 * 停梯状态： 1-正常 2-停梯
	 */
	private final static Integer[] ELEVATOR_STOP_TYPES = {0, 1, 2};

	//1:非年审，2:年审
	private final static Integer[] AUDIT_TYPE = {0, 1, 2};


	//1:今日,2:进行中 3：已完成
	/**
	 * 1:今日,2:进行中 3：已完成
	 */
	private final static Integer[] PLAN_TYPE = {0, 1, 2, 3};

	@Override
	public MaintainPlanContentHomeListVo selectMaintainPlanContentPage(PlanContentSearchDTO planContentSearchDTO) {
		planContentSearchDTO.setUserId(AuthUtil.getUserId());
		MaintainPlanContentHomeListVo maintainPlanContentHomeListVo = new MaintainPlanContentHomeListVo();
		maintainPlanContentHomeListVo.setPlanContentType(getplanContentType(planContentSearchDTO));
		List<MaintainPlanContentVo> disFinishList = new ArrayList<>(16);
		List<PlanContentElevatorVo> planContentElevatorVos = new ArrayList<>(50);

		//保养维修的查询条件
		List<Integer> statusList = new ArrayList<>(5);
		statusList.add(TaskStatusEnum.BY_DISABLE.getStatus());
		statusList.add(TaskStatusEnum.BY_PROCESSED.getStatus());
		statusList.add(TaskStatusEnum.BY_FINISH.getStatus());
		statusList.add(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus());
		planContentSearchDTO.setStatusList(statusList);


		//拼接配件查询条件
		PlanContentSearchDTO planContentSearchDTO1 = new PlanContentSearchDTO();
		BeanUtil.copyProperties(planContentSearchDTO, planContentSearchDTO1);
		planContentSearchDTO1.setTypeStatus(MaintainPlanContentEnum.MAINTAIN_PARTS.getId());
		List<Integer> statusList3 = new ArrayList<>(5);
		statusList3.add(TaskStatusEnum.PARTS_TO_START.getStatus());
		statusList3.add(TaskStatusEnum.PARTS_CHANGE.getStatus());
		planContentSearchDTO1.setStatusList(statusList3);

		List<Dict> dicts = dictService.list(Wrappers.<Dict>lambdaQuery().eq(Dict::getCode, "fault_problem"));
		List<PlanContentElevatorVo> test = new ArrayList<>(50);
		if (planContentSearchDTO.getTypeStatus() == null) {
			//如果查询工单类型为空，查询所有的工单

			//保养维修工单
			List<PlanContentElevatorVo> planContentElevatorVos3 = baseMapper.selectMaintainPlanContent(planContentSearchDTO, AuthUtil.getTenantId());
			planContentElevatorVos.addAll(planContentElevatorVos3);

			//配件工单
			List<PlanContentElevatorVo> planContentElevatorVos4 = baseMapper.selectMaintainPlanContent(planContentSearchDTO1, AuthUtil.getTenantId());
			planContentElevatorVos.addAll(planContentElevatorVos4);

			//事务工单
			List<PlanContentElevatorVo> planAffairList = getPlanAffairList(planContentSearchDTO, PLAN_TYPE[2]);
			planContentElevatorVos.addAll(planAffairList);

			//事务工单
			List<PlanContentElevatorVo> planCheckList = getPlanCheckList(planContentSearchDTO, PLAN_TYPE[2]);
			planContentElevatorVos.addAll(planCheckList);

			test.addAll(planAffairList);
		} else if (planContentSearchDTO.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_PARTS.getId()) {
			//只查配件工单
			List<PlanContentElevatorVo> planContentElevatorVos4 = baseMapper.selectMaintainPlanContent(planContentSearchDTO1, AuthUtil.getTenantId());
			planContentElevatorVos.addAll(planContentElevatorVos4);
		} else if (planContentSearchDTO.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_AFFAIR.getId()) {
			List<PlanContentElevatorVo> planAffairList = getPlanAffairList(planContentSearchDTO, PLAN_TYPE[2]);
			planContentElevatorVos.addAll(planAffairList);
		} else if (planContentSearchDTO.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_CHECK.getId()) {
			List<PlanContentElevatorVo> planAffairList = getPlanCheckList(planContentSearchDTO, PLAN_TYPE[2]);
			planContentElevatorVos.addAll(planAffairList);
		} else {
			//只查维修或者保养工单
			List<PlanContentElevatorVo> planContentElevatorVos3 = baseMapper.selectMaintainPlanContent(planContentSearchDTO, AuthUtil.getTenantId());
			planContentElevatorVos.addAll(planContentElevatorVos3);
		}


		//查询逾期的工单
		long today = 0L;
		long between = DateUtil.between(planContentSearchDTO.getBeginTime(), planContentSearchDTO.getEndTime(), DateUnit.DAY);
		final Integer yyyyMMdd1 = Convert.toInt(DateUtil.format(new Date(), "yyyyMMdd"));
		final Integer yyyyMMdd2 = Convert.toInt(DateUtil.format(planContentSearchDTO.getBeginTime(), "yyyyMMdd"));
		if (between == today && yyyyMMdd1.equals(yyyyMMdd2)) {

			//设置维修保养的查询条件
			PlanContentSearchDTO planContentSearchDTO2 = new PlanContentSearchDTO();
			List<Integer> statusList2 = new ArrayList<>(5);

			statusList2.add(TaskStatusEnum.BY_DISABLE.getStatus());
			statusList2.add(TaskStatusEnum.BY_PROCESSED.getStatus());
			statusList2.add(TaskStatusEnum.BY_FINISH.getStatus());
			statusList2.add(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus());
			planContentSearchDTO2.setStatusList(statusList);
			planContentSearchDTO2.setBeginTime(DateUtil.offsetDay(new Date(), -365));
			planContentSearchDTO2.setEndTime(DateUtil.endOfDay(DateUtil.yesterday()));
			planContentSearchDTO2.setUserId(AuthUtil.getUserId());


			//维修记录的查询条件
			PlanContentSearchDTO planContentSearchDTO4 = new PlanContentSearchDTO();
			BeanUtil.copyProperties(planContentSearchDTO2, planContentSearchDTO4);
			List<Integer> statusList4 = new ArrayList<>(5);
			statusList4.add(TaskStatusEnum.PARTS_TO_START.getStatus());
			statusList4.add(TaskStatusEnum.PARTS_CHANGE.getStatus());
			planContentSearchDTO4.setStatusList(statusList4);
			planContentSearchDTO4.setTypeStatus(MaintainPlanContentEnum.MAINTAIN_PARTS.getId());

			if (planContentSearchDTO.getTypeStatus() == null) {
				//查询所有的工单类型
				//保养维修查询
				List<PlanContentElevatorVo> planContentElevatorVos2 = baseMapper.selectMaintainPlanContent(planContentSearchDTO2, AuthUtil.getTenantId());
				planContentElevatorVos.addAll(planContentElevatorVos2);

				//配件查询
				List<PlanContentElevatorVo> planContentElevatorVos4 = baseMapper.selectMaintainPlanContent(planContentSearchDTO4, AuthUtil.getTenantId());
				planContentElevatorVos.addAll(planContentElevatorVos4);

				//事务工单查询
				List<PlanContentElevatorVo> planAffairList = getPlanAffairList(planContentSearchDTO, PLAN_TYPE[1]);
				planContentElevatorVos.addAll(planAffairList);

				//质检工单查询
				List<PlanContentElevatorVo> planCheckList = getPlanCheckList(planContentSearchDTO, PLAN_TYPE[1]);
				planContentElevatorVos.addAll(planCheckList);

				test.addAll(planAffairList);
			} else if (planContentSearchDTO.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_PARTS.getId()) {
				//配件查询
				List<PlanContentElevatorVo> planContentElevatorVos4 = baseMapper.selectMaintainPlanContent(planContentSearchDTO4, AuthUtil.getTenantId());
				planContentElevatorVos.addAll(planContentElevatorVos4);
			} else if (planContentSearchDTO.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_AFFAIR.getId()) {
				//事务工单查询
				List<PlanContentElevatorVo> planAffairList = getPlanAffairList(planContentSearchDTO, PLAN_TYPE[1]);
				planContentElevatorVos.addAll(planAffairList);
			} else if (planContentSearchDTO.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_CHECK.getId()) {
				//事务工单查询
				List<PlanContentElevatorVo> planCheckList = getPlanCheckList(planContentSearchDTO, PLAN_TYPE[1]);
				planContentElevatorVos.addAll(planCheckList);
			} else {
				planContentSearchDTO2.setTypeStatus(planContentSearchDTO.getTypeStatus());
				//保养或者维修查询
				List<PlanContentElevatorVo> planContentElevatorVos2 = baseMapper.selectMaintainPlanContent(planContentSearchDTO2, AuthUtil.getTenantId());
				planContentElevatorVos.addAll(planContentElevatorVos2);
			}

			//查询工单类型的总数
			planContentSearchDTO.setBeginTime2(planContentSearchDTO2.getBeginTime());
			planContentSearchDTO.setEndTime2(planContentSearchDTO2.getEndTime());
			planContentSearchDTO.setPlanDateBeginTime(DateUtil.offsetDay(new Date(), -7));

			maintainPlanContentHomeListVo.setPlanContentType(getplanContentType(planContentSearchDTO));

		}

		Map<Long, List<User>> userMap = getPlanUserList(planContentElevatorVos);
		List<String> planDates = planContentElevatorVos.stream().map(PlanContentElevatorVo::getPlanDate).distinct().collect(Collectors.toList());
		Collections.sort(planDates);
		Map<String, List<PlanContentElevatorVo>> collect = planContentElevatorVos.stream().collect(Collectors.groupingBy(PlanContentElevatorVo::getPlanDate));
		for (String planDate : planDates) {
			MaintainPlanContentVo maintainPlanContentVo = new MaintainPlanContentVo();
			List<PlanContentElevatorVo> planContentElevatorVos1 = collect.get(planDate);

			//如果是今日剔除逾期7天以前的保养工单
			List<PlanContentElevatorVo> removeList = new ArrayList<>(50);
			if (between == today && yyyyMMdd1.equals(yyyyMMdd2)) {
				for (PlanContentElevatorVo planContentElevatorVo : planContentElevatorVos1) {
					if (planContentElevatorVo.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_BY.getId()) {
						final DateTime time = DateUtil.parse(planContentElevatorVo.getPlanDate(), "yyyy-MM-dd");
						final Integer planDateNo1 = Convert.toInt(DateUtil.format(time, "yyyyMMdd"));
						final Integer planDateNo2 = Convert.toInt(DateUtil.format(DateUtil.offsetDay(new Date(), -7), "yyyyMMdd"));
						if (planDateNo1 < planDateNo2) {
							removeList.add(planContentElevatorVo);
						}
					} else if (planContentElevatorVo.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_WX.getId()) {
						//2023-04-15 新增需求去除维修已经关闭的工单
						if (planContentElevatorVo.getStatus() == TaskStatusEnum.WX_CLOSED.getStatus()) {
							removeList.add(planContentElevatorVo);
						}
					}
				}
				planContentElevatorVos1.removeAll(removeList);
			}
			List<Long> buildingIds = planContentElevatorVos1.stream().map(PlanContentElevatorVo::getBuildingId).distinct().collect(Collectors.toList());
			Map<Long, List<PlanContentElevatorVo>> listMap = planContentElevatorVos1.stream().collect(Collectors.groupingBy(PlanContentElevatorVo::getBuildingId));
			List<MaintainPlanContentListVo> buildingVoList = new ArrayList<>(16);
			Integer planDateCounts = 0;
			//项目信息
			for (Long buildingId : buildingIds) {
				List<PlanContentElevatorVo> planContentElevatorVos2 = listMap.get(buildingId);
				MaintainPlanContentListVo buildingVo = new MaintainPlanContentListVo();
				BeanUtil.copyProperties(planContentElevatorVos2.get(0), buildingVo);

				if (StrUtil.isNotEmpty(planContentSearchDTO.getLatitude()) && StrUtil.isNotEmpty(planContentSearchDTO.getLongitude())) {
					BigDecimal distance = DistanceUtils.getDistance(Convert.toDouble(planContentSearchDTO.getLongitude()), Convert.toDouble(planContentSearchDTO.getLatitude()), Convert.toDouble(buildingVo.getLongitude()), Convert.toDouble(buildingVo.getLatitude()));
					final String kmDesc = distance.divide(Convert.toBigDecimal(1000), 1, BigDecimal.ROUND_HALF_UP).toString();
					buildingVo.setKmDesc(kmDesc + "km");
				}

				buildingVo.setBuildingName(buildingVo.getBuildingName());
				List<PlanContentElevatorVo> elevatorVoList = new ArrayList<>(16);
				planDateCounts = planDateCounts + planContentElevatorVos2.size();
				//电梯信息排序
				for (PlanContentElevatorVo planContentElevatorVo : planContentElevatorVos2) {
					Integer typeStatus = planContentElevatorVo.getTypeStatus();
					Integer status = planContentElevatorVo.getStatus();
					String date = planContentElevatorVo.getPlanDate() + " 00:00:00";
					DateTime parse = DateUtil.parse(date, "yyyy-MM-dd HH:mm:ss");
					DateTime dateTime = DateUtil.beginOfDay(new Date());
					Boolean isDeferred = Convert.toBool(planContentElevatorVo.getIsDeferred(), false);
					Integer elevatorIsStop = Convert.toInt(planContentElevatorVo.getElevatorIsStop(), -1);


					//2023-05-12 新增逾期逻辑需求
					//表示年审工单
					if (typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId()) {
						if (AUDIT_TYPE[2].equals(planContentElevatorVo.getAuditType())) {
							Integer date1 = Convert.toInt(DateUtil.format(DateUtil.parse(planContentElevatorVo.getPlanDate(), "yyyy-MM-dd"), "yyyyMMdd"));
							Integer date2 = Convert.toInt(DateUtil.format(new Date(), "yyyyMMdd"));
							if (date1 <= date2) {
								Date date5 = planContentElevatorVo.getMaintainSignatureTime() != null ? planContentElevatorVo.getMaintainSignatureTime() : new Date();
								Integer date3 = Convert.toInt(DateUtil.format(date5, "yyyyMMdd"));
								Integer date4 = Convert.toInt(DateUtil.format(planContentElevatorVo.getOverdueDate(), "yyyyMMdd"));
								if (date3 > date4) {
									planContentElevatorVo.setTimeliness("逾期" + DateUtil.betweenDay(date5, planContentElevatorVo.getOverdueDate(), true) + "天");
								}
							}
						}
					}

					//获取工单的状态名称
					planContentElevatorVo.setStatusName(getPlanStatusName(planContentElevatorVo));

					//进行中默认未签到状态
					if (typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && status == TaskStatusEnum.BY_DISABLE.getStatus() || typeStatus == MaintainPlanContentEnum.MAINTAIN_WX.getId() && status == TaskStatusEnum.WX_TO_START.getStatus() || typeStatus == MaintainPlanContentEnum.MAINTAIN_PARTS.getId() && status == TaskStatusEnum.PARTS_TO_START.getStatus() || typeStatus == MaintainPlanContentEnum.MAINTAIN_AFFAIR.getId() && status == TaskStatusEnum.SW_TO_START.getStatus()) {
						List<PlanUserSignDetailVo> signUsers = new ArrayList<>(16);
						List<String> list = Arrays.asList(planContentElevatorVo.getUserIds().split(","));
						List<User> users = getPlanUsers(userMap, list);
						for (User user : users) {
							PlanUserSignDetailVo planUserSignDetailVo = new PlanUserSignDetailVo();
							planUserSignDetailVo.setPlanId(planContentElevatorVo.getPlanId());
							planUserSignDetailVo.setUserName(user.getRealName());
							signUsers.add(planUserSignDetailVo);
						}
						planContentElevatorVo.setSignUsers(signUsers);
					}

					//2023-05-16 超时逻辑区分状态需求
					if (typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && planContentElevatorVo.getMaintainSignatureTime() != null) {
						Integer days = Convert.toInt(DateUtil.betweenDay(DateUtil.parse(planContentElevatorVo.getPlanDate()), planContentElevatorVo.getMaintainSignatureTime(), false), 0);
						if (days > 0) {
							planContentElevatorVo.setOverdueName("超时" + days + "天");
						} else {
							planContentElevatorVo.setOverdueName(null);
						}
					}


					//维修工单时获取维修故障原因
					if (typeStatus == MaintainPlanContentEnum.MAINTAIN_WX.getId()) {
						if (StrUtil.isNotEmpty(planContentElevatorVo.getProblemItem())) {
							List<String> ids = Arrays.asList(planContentElevatorVo.getProblemItem().split(","));
							List<Dict> dicts2 = dictService.getList(dicts, ids);
							if (dicts2.size() > 0) {
								List<String> strings = dicts2.stream().map(Dict::getDictValue).collect(Collectors.toList());
								planContentElevatorVo.setProblemItemNames(strings);
							}
						}
					}


					//排序
					if (parse.getTime() < dateTime.getTime() && typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && status == TaskStatusEnum.BY_PROCESSED.getStatus()) {
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(30041942495081.69)));
						planContentElevatorVo.setWeight(102);
					} else if (parse.getTime() < dateTime.getTime() && typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && status == TaskStatusEnum.BY_FINISH.getStatus()) {
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(1430568690241.985)));
						planContentElevatorVo.setWeight(101);
					} else if (parse.getTime() < dateTime.getTime() && typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && status == TaskStatusEnum.BY_DISABLE.getStatus()) {
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(68122318582.95168)));
						planContentElevatorVo.setWeight(100);
					} else if (typeStatus == MaintainPlanContentEnum.MAINTAIN_WX.getId() && status == TaskStatusEnum.WX_UNDER_WAY.getStatus() && elevatorIsStop.equals(ELEVATOR_STOP_TYPES[2])) {
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(3243919932.521509)));
						planContentElevatorVo.setWeight(99);
					} else if (typeStatus == MaintainPlanContentEnum.MAINTAIN_WX.getId() && status == TaskStatusEnum.WX_SIGN_FINISH.getStatus() && elevatorIsStop.equals(ELEVATOR_STOP_TYPES[2])) {
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(154472377.7391195)));
						planContentElevatorVo.setWeight(98);
					} else if (typeStatus == MaintainPlanContentEnum.MAINTAIN_WX.getId() && status == TaskStatusEnum.WX_TO_START.getStatus() && elevatorIsStop.equals(ELEVATOR_STOP_TYPES[2])) {
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(7355827.511386641)));
						planContentElevatorVo.setWeight(97);
					} else if (isDeferred && typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && status == TaskStatusEnum.BY_PROCESSED.getStatus()) {
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(7355827.511386641)));
						planContentElevatorVo.setWeight(96);
					} else if (isDeferred && typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && status == TaskStatusEnum.BY_FINISH.getStatus()) {
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(7355827.511386641)));
						planContentElevatorVo.setWeight(95);
					} else if (isDeferred && typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && status == TaskStatusEnum.BY_DISABLE.getStatus()) {
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(350277.500542221)));
						planContentElevatorVo.setWeight(94);
					} else if (typeStatus == MaintainPlanContentEnum.MAINTAIN_WX.getId() && status == TaskStatusEnum.WX_UNDER_WAY.getStatus() && elevatorIsStop.equals(ELEVATOR_STOP_TYPES[1])) {
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(16679.880978201)));
						planContentElevatorVo.setWeight(93);
					} else if (typeStatus == MaintainPlanContentEnum.MAINTAIN_WX.getId() && status == TaskStatusEnum.WX_SIGN_FINISH.getStatus() && elevatorIsStop.equals(ELEVATOR_STOP_TYPES[1])) {
						planContentElevatorVo.setWeight(92);
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(794.280046581)));
					} else if (typeStatus == MaintainPlanContentEnum.MAINTAIN_WX.getId() && status == TaskStatusEnum.WX_TO_START.getStatus() && elevatorIsStop.equals(ELEVATOR_STOP_TYPES[1])) {
						planContentElevatorVo.setWeight(91);
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(37.822859361)));
					} else if (!isDeferred && typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && status == TaskStatusEnum.BY_PROCESSED.getStatus()) {
						planContentElevatorVo.setWeight(90);
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(1.801088541)));
					} else if (!isDeferred && typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && status == TaskStatusEnum.BY_FINISH.getStatus()) {
						planContentElevatorVo.setWeight(89);
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(0.085766121)));
					} else if (!isDeferred && typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && status == TaskStatusEnum.BY_DISABLE.getStatus()) {
						planContentElevatorVo.setWeight(88);
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(0.004084101)));
					} else if (typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && status == TaskStatusEnum.BY_PROCESSED.getStatus()) {
						planContentElevatorVo.setWeight(87);
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(0.000194481)));
					} else if (typeStatus == MaintainPlanContentEnum.MAINTAIN_BY.getId() && status == TaskStatusEnum.BY_FINISH.getStatus()) {
						planContentElevatorVo.setWeight(86);
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(0.000009261)));
					} else if (typeStatus == MaintainPlanContentEnum.MAINTAIN_WX.getId() && status == TaskStatusEnum.WX_UNDER_WAY.getStatus()) {
						planContentElevatorVo.setWeight(85);
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(0.000000441)));
					} else if (typeStatus == MaintainPlanContentEnum.MAINTAIN_WX.getId() && status == TaskStatusEnum.WX_SIGN_FINISH.getStatus()) {
						planContentElevatorVo.setWeight(84);
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(0.000000021)));
					} else {
						planContentElevatorVo.setWeight(83);
						buildingVo.setWeight(buildingVo.getWeight().add(Convert.toBigDecimal(0.000000001)));
					}
					elevatorVoList.add(planContentElevatorVo);
				}
				Collections.sort(elevatorVoList);
				buildingVo.setList(elevatorVoList);
				buildingVoList.add(buildingVo);
			}

			if (buildingVoList.size() > 0) {
				//项目信息排序
				//Collections.sort(buildingVoList);
				buildingVoList.sort(Comparator.comparing(MaintainPlanContentListVo::getWeight).reversed());
				maintainPlanContentVo.setPlanDate(planDate + "(" + planDateCounts + ")");
				maintainPlanContentVo.setMaintainPlanContentListVos(buildingVoList);
				disFinishList.add(maintainPlanContentVo);
			}
			maintainPlanContentHomeListVo.setDisFinishList(disFinishList);
		}

		//查询已经完成的工单信息
		List<MaintainPlanContentVo> finishList = getFinishList(planContentSearchDTO, maintainPlanContentHomeListVo);
		maintainPlanContentHomeListVo.setFinishList(finishList.size() > 0 ? finishList : null);
		return maintainPlanContentHomeListVo;
	}

	@Override
	public boolean update(MaintainPlanContent maintainPlanContent) {
		Integer status = maintainPlanContent.getStatus();
		MaintainPlanContent planContent = this.getById(maintainPlanContent.getId());

		//保养的逻辑处理
		if (planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_BY.getId())) {
			//表示逾期
			Integer isDeferred = 1;
			if (status != null) {
				MaintainPlanContentExt maintainPlanContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, maintainPlanContent.getId()));
				if (status.equals(TaskStatusEnum.BY_SIGN.getStatus())) {
					maintainPlanContentExt.setPlanEndTime(new Date());
				} else if (status.equals(TaskStatusEnum.BY_FINISH.getStatus())) {
					List<MaintainSign> list = signService.list(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, maintainPlanContent.getId()).orderByDesc(MaintainSign::getCreateTime));
					Long timeInterval = 0L;
					if (planContent.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_BY.getId()) {
						// 计算耗时，单位：分钟（向上取整）
						timeInterval = list.stream()
							.filter(maintainSign -> maintainSign.getSignOutTime() != null && maintainSign.getSignTime() != null)
							.mapToLong(maintainSign -> maintainSign.getSignOutTime().getTime() - maintainSign.getSignTime().getTime())
							.sum();
						timeInterval = (long) Math.ceil(timeInterval / 60000.0);

						// 计算工单实际作业时长
						List<DateUtils.TimePeriod> periods = list.stream()
							.map(maintainSign -> new DateUtils.TimePeriod(maintainSign.getSignTime(), maintainSign.getSignOutTime()))
							.collect(Collectors.toList());
						maintainPlanContentExt.setWorkDuration(Convert.toInt(DateUtils.calculateWorkDuration(periods)));
					} else if (planContent.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_WX.getId()) {
						if (list.size() > 0) {
							MaintainSign maintainSign = list.get(0);
							timeInterval = DateUtil.between(maintainSign.getCreateTime(), new Date(), DateUnit.MINUTE);
						}
					}
					maintainPlanContentExt.setWorkMinute(Convert.toInt(timeInterval));
				} else if (status.equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())) {
					maintainPlanContentExt.setOverdueDay(DateUtil.betweenDay(planContent.getPlanDate(), new Date(), true) == 0 ? null : 1);
				}
				maintainPlanContentExtService.updateById(maintainPlanContentExt);
			} else if (maintainPlanContent.getIsDeferred().equals(isDeferred)) {
				maintainPlanContent.setPlanDate(DateUtil.tomorrow());
			}
			//维修的逻辑处理
		} else if (planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_WX.getId())) {
			//维修类型1:撤回，2:关闭
			int wxTypeStatuss = 2;
			if (maintainPlanContent.getWxTypeStatus() != null) {
				if (planContent.getStatus() != TaskStatusEnum.WX_TO_START.getStatus() || planContent.getStatus() != TaskStatusEnum.WX_PENDING.getStatus()) {
					throw new ServiceException("工单已经开始,不能关闭或者撤回");
				}
				if (maintainPlanContent.getWxTypeStatus() == wxTypeStatuss) {
					log.info("发送给报障人和委派的维修员");
					planContent.setStatus(TaskStatusEnum.WX_CLOSED.getStatus());
				}
			} else if (status != null && status.equals(TaskStatusEnum.WX_SIGN_FINISH.getStatus())) {
				List<MaintainSign> list = signService.list(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, maintainPlanContent.getId()).orderByDesc(MaintainSign::getCreateTime));
				Long timeInterval = 0L;
				for (MaintainSign maintainSign : list) {
					timeInterval = timeInterval + Convert.toLong(maintainSign.getTimeInterval(), 0L);
				}
				MaintainPlanContentExt maintainPlanContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, maintainPlanContent.getId()));
				maintainPlanContentExt.setWorkMinute(Convert.toInt(timeInterval));
				maintainPlanContentExt.setWorkMill(timeInterval * 60000);
				maintainPlanContentExt.setPlanEndTime(new Date());
				maintainPlanContentExt.setOverdueDay(DateUtil.betweenDay(planContent.getPlanDate(), new Date(), true) == 0 ? null : 1);
				maintainPlanContentExtService.updateById(maintainPlanContentExt);
			}

		} else if (planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_PARTS.getId())) {
			if (status != null && status.equals(TaskStatusEnum.PARTS_FINISH.getStatus())) {
				List<MaintainSign> list = signService.list(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, maintainPlanContent.getId()).orderByDesc(MaintainSign::getCreateTime));
				Long timeInterval = 0L;
				for (MaintainSign maintainSign : list) {
					timeInterval = timeInterval + maintainSign.getTimeInterval();
				}
				MaintainPlanContentExt maintainPlanContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, maintainPlanContent.getId()));
				maintainPlanContentExt.setWorkMinute(Convert.toInt(timeInterval));
				maintainPlanContentExt.setPlanEndTime(new Date());
				maintainPlanContentExt.setOverdueDay(DateUtil.betweenDay(planContent.getPlanDate(), new Date(), true) == 0 ? null : 1);
				maintainPlanContentExtService.updateById(maintainPlanContentExt);
			}
		}
		return this.updateById(maintainPlanContent);
	}

	@Override
	public Map<String, Object> getPlanLocationType(Long planId) {
		MaintainPlanContent planContent = super.getById(planId);
		List<PlanDetailLocationTypeVO> planDetailLocationTypeVOS = null;
		// 任务开始前
		if (planContent.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())) {
			List<Long> templateIds = planTemplateService.list(Wrappers.<MaintainPlanTemplate>lambdaQuery()
				.eq(MaintainPlanTemplate::getPlanId, planId)).stream().map(MaintainPlanTemplate::getTemplateId).distinct().collect(Collectors.toList());
			planDetailLocationTypeVOS = baseMapper.selectPlanDetailLocationType(templateIds);
			Map<Long, List<PlanDetailLocationTypeVO>> tltMap = planDetailLocationTypeVOS.stream().filter(e -> e.getContentId() != null).collect(Collectors.groupingBy(PlanDetailLocationTypeVO::getId));
			planDetailLocationTypeVOS = ForestNodeMerger.merge(planDetailLocationTypeVOS.stream().filter(e -> e.getContentId() == null).collect(Collectors.toList()));
			planDetailLocationTypeVOS.forEach(e -> {
				e = doTltCount(e, new HashMap<>(), tltMap);
			});
			// 过滤关联工作项为0的分类
			planDetailLocationTypeVOS = planDetailLocationTypeVOS.stream().filter(e -> e.getWorkItemCount() > 0 && e.getParentId() == 0).collect(Collectors.toList());
		} else {
			List<MaintainCheckHistory> planCheckHistoryList = checkHistoryService.list(Wrappers.<MaintainCheckHistory>lambdaQuery().eq(MaintainCheckHistory::getPlanId, planId));
			List<Long> templateIds = planCheckHistoryList.stream().map(MaintainCheckHistory::getTemplateId).distinct().collect(Collectors.toList());
			// 截取第一位为根节点
			planDetailLocationTypeVOS = planCheckHistoryList.stream().map(e -> {
				PlanDetailLocationTypeVO typeVO = new PlanDetailLocationTypeVO();
				Long tltId = Long.valueOf(e.getTltIds().split(",")[0]);
				String tltName = e.getTltNames().split("&&")[0];
				typeVO.setTltId(tltId);
				typeVO.setTltName(tltName);
				return typeVO;
			}).collect(Collectors.toList());
			// 去重
			planDetailLocationTypeVOS = planDetailLocationTypeVOS.stream().collect(Collectors.collectingAndThen(
				Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(e -> e.getTltId() + ";" + e.getTltName()))), ArrayList::new
			));
			planDetailLocationTypeVOS.forEach(e -> {
				Integer workItemCount = Math.toIntExact(planCheckHistoryList.stream().filter(j -> Func.toLongList(j.getTltIds()).contains(e.getTltId())).count());
				e.setWorkItemCount(workItemCount);
			});
		}


		//2024-02-27新增多模板的信息返回
		List<MaintainTemplate> maintainTemplates = planTemplateService.listPlanTemplate(planId);
		Map<String, Object> map = new HashMap<>(2);
		map.put("location", planDetailLocationTypeVOS);
		map.put("template", maintainTemplates);

		return map;
	}

	@Override
	public HashMap<String, Object> selectPlanDetail(Long planId) {
		MaintainPlanContent maintainPlanContent = super.getById(planId);
		if (maintainPlanContent == null) {
			throw new ServiceException("工单项id不能为空");
		}
		List<MaintainPlanContentUser> planContentUsers = planContentUserService.list(Wrappers.<MaintainPlanContentUser>lambdaQuery().eq(MaintainPlanContentUser::getPlanId, planId));
		List<MaintainSign> signList = signService.list(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, planId));
		planContentUsers = planContentUsers.stream().filter(e -> {
			User user = userService.getById(e.getUserId());
			e.setUserName(user.getRealName());
			e.setPhone(user.getPhone());
			int userSignCount = (int) signList.stream().filter(t -> t.getUserId().equals(e.getUserId())).count();
			e.setUserSignCount(userSignCount);
			if (maintainPlanContent.getStatus().equals(TaskStatusEnum.BY_FINISH.getStatus()) && maintainPlanContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_BY.getId())) {
				return userSignCount > 0;
			} else if (maintainPlanContent.getStatus().equals(TaskStatusEnum.WX_SIGN_FINISH.getStatus()) && maintainPlanContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_WX.getId())) {
				return userSignCount > 0;
			} else if (maintainPlanContent.getStatus().equals(TaskStatusEnum.SW_SIGN_FINISH.getStatus()) && maintainPlanContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_AFFAIR.getId())) {
				return userSignCount > 0;
			} else if (maintainPlanContent.getStatus().equals(TaskStatusEnum.ZJ_SIGN_FINISH.getStatus()) && maintainPlanContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_CHECK.getId())) {
				return userSignCount > 0;
			} else {
				return true;
			}
		}).collect(Collectors.toList());

		SimpleElevatorPlanInfoDTO elevator = elevatorService.getSimpleElevatorPlanInfo(maintainPlanContent.getElevatorId());
		BuildingContacts buildingContacts = buildingContactsService.getOne(Wrappers.<BuildingContacts>lambdaQuery().eq(BuildingContacts::getBuildingId, elevator.getBuildingId()));
		MaintainPlanContentExt maintainPlanContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, planId));
		//针对维修故障原因新增名称给前端
		String malfunctionType = maintainPlanContentExt.getMalfunctionType();
		if (StrUtil.isNotEmpty(malfunctionType)) {
			Map<Long, List<WxFaultCause>> wxFaultCauseMap = wxFaultCauseService.list().stream().collect(Collectors.groupingBy(WxFaultCause::getId));
			List<String> list = Arrays.asList(malfunctionType.split(","));
			List<String> malfunctionTypeNames = new ArrayList<>(10);
			for (String id : list) {
				List<WxFaultCause> wxFaultCauses = wxFaultCauseMap.get(Convert.toLong(id));
				if (wxFaultCauses != null && wxFaultCauses.size() > 0) {
					malfunctionTypeNames.add(wxFaultCauses.get(0).getFaultName());
				}
			}
			maintainPlanContentExt.setMalfunctionTypeNames(malfunctionTypeNames);
		}

		HashMap<String, Object> planDetailMap = new HashMap<>(2);
		planDetailMap.put("planDate", maintainPlanContent.getPlanDate());
		planDetailMap.put("finishDate", DateUtil.format(maintainPlanContent.getFinishDate(), "yyyy-MM-dd HH:mm"));
		// 根据工单状态封装及时性 时效性标签描述
		if (maintainPlanContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_BY.getId())) {


			if (maintainPlanContent.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus()) || maintainPlanContent.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())) {

				if (maintainPlanContentExt.getAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus()) && ObjectUtil.isNotEmpty(maintainPlanContentExt.getOverdueDate())) {
					long maintainSignatureTime = DateUtil.parse(DateUtil.format(maintainPlanContentExt.getMaintainSignatureTime(), "yyyy-MM-dd")).getTime();
					long overdueDate = maintainPlanContentExt.getOverdueDate().getTime();
					if (maintainSignatureTime > overdueDate) {
						long betweenDay = DateUtil.between(maintainPlanContentExt.getOverdueDate(), maintainPlanContentExt.getMaintainSignatureTime(), DateUnit.DAY);
						planDetailMap.put("overdueName", "逾期" + betweenDay + "天");
					}
				}

				long betweenDay = DateUtil.between(maintainPlanContent.getPlanDate(), maintainPlanContentExt.getMaintainSignatureTime(), DateUnit.DAY);
				if (betweenDay > 0) {
					if (maintainPlanContent.getPlanDate().compareTo(maintainPlanContentExt.getMaintainSignatureTime()) < 0) {
						planDetailMap.put("timeliness", "超时" + betweenDay + "天");
					}
				} else if (betweenDay == 0) {
					planDetailMap.put("timeliness", WorkTrackStatusEnum.IN_TIME.getTypeName());
				}
			} else {

				if (maintainPlanContentExt.getAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus()) && ObjectUtil.isNotEmpty(elevator.getOverdueDate())) {
					long planDate = maintainPlanContent.getPlanDate().getTime();
					long overdueDate = elevator.getOverdueDate().getTime();
					long nowDate = DateUtil.parse(DateUtil.today()).getTime();
					if (planDate <= nowDate && nowDate > overdueDate) {
						long betweenDay = DateUtil.between(elevator.getOverdueDate(), DateUtil.date(), DateUnit.DAY);
						planDetailMap.put("overdueName", "逾期" + betweenDay + "天");
					}
				}

				long betweenDay = DateUtil.between(maintainPlanContent.getPlanDate(), new Date(), DateUnit.DAY);
				if (betweenDay > 0) {
					if (maintainPlanContent.getPlanDate().compareTo(DateUtil.date()) < 0) {
						planDetailMap.put("timeliness", "超时" + betweenDay + "天");
					}
				}
			}
		}
		List<SimpleTemplateInfoVO> templateInfoVOS = baseMapper.getPlanTemplateSimpleInfo(maintainPlanContent.getId());
		planDetailMap.put("templateInfo", templateInfoVOS);
		planDetailMap.put("status", maintainPlanContent.getStatus());
		planDetailMap.put("statusName", TaskStatusEnum.getTaskName(maintainPlanContent.getTypeStatus(), maintainPlanContent.getStatus()));
		planDetailMap.put("users", planContentUsers);
		planDetailMap.put("serviceTel", "076088814888");

		// 获取当天本人同一台梯是否存在签到记录的签到图片
		ElevatorLastPlanVO lastSignImg = signService.selectUserLastSignImgByElevator(AuthUtil.getUserId(), maintainPlanContent.getElevatorId());
		planDetailMap.put("lastSignImg", lastSignImg);

		//2022-11-19新增年审标识
		planDetailMap.put("auditType", maintainPlanContentExt.getAuditType());

		if (ObjectUtil.isNotEmpty(buildingContacts)) {
			planDetailMap.put("estateTel", buildingContacts.getPhone());
		}
		planDetailMap.put("maintainPlanContentExt", maintainPlanContentExt);
		planDetailMap.put("maintainSignature", Boolean.FALSE);
		if (maintainPlanContent.getStatus().equals(TaskStatusEnum.BY_FINISH.getStatus())) {
			int count = signtureService.count(Wrappers.<MaintainSignture>lambdaQuery().eq(MaintainSignture::getPlanId, planId).eq(MaintainSignture::getSignType, 1));
			if (planContentUsers.size() == count) {
				planDetailMap.put("maintainSignature", Boolean.TRUE);
			}
		}

		planDetailMap.put("signatureEstateStatus", signtureService.signatureEstateStatus(planId));

		// 计算工单实际作业时长
		List<DateUtils.TimePeriod> periods = signList.stream().filter(e -> Func.isNotEmpty(e.getSignOutTime()))
			.map(maintainSign -> new DateUtils.TimePeriod(maintainSign.getSignTime(), maintainSign.getSignOutTime()))
			.collect(Collectors.toList());
		planDetailMap.put("workDuration", Convert.toInt(DateUtils.calculateWorkDuration(periods)));


		return planDetailMap;
	}

	@Override
	public List<PlanTemplateVO> getPlanWorkItem(Long planId, Long tltId, Long templateId) {
		MaintainPlanContent planContent = super.getById(planId);
		List<PlanTemplateVO> templateVOS = new ArrayList<>();
		if (planContent.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())) {
			List<Long> templateIds;
			if (templateId != null) {
				templateIds = new ArrayList<>(1);
				templateIds.add(templateId);
			} else {
				templateIds = planTemplateService.list(Wrappers.<MaintainPlanTemplate>lambdaQuery()
					.eq(MaintainPlanTemplate::getPlanId, planId).orderByAsc(MaintainPlanTemplate::getSort)).stream().map(MaintainPlanTemplate::getTemplateId).collect(Collectors.toList());
			}
			List<Long> tltIds = getTltIds(tltId, templateIds);
			if (tltIds.size() == 0) {
				return new ArrayList<>();
			}
			templateIds.forEach(e -> {
				PlanTemplateVO planTemplateVO = new PlanTemplateVO();
				String templateName = templateService.getById(e).getName();
				planTemplateVO.setTemplateId(e);
				planTemplateVO.setTemplateName(templateName);
				List<PlanTemplateTypeVO> planTemplateTypeVOS = baseMapper.selectPlanTemplateType(tltIds, e);
				planTemplateVO.setTemplateTypeVOS(change(planTemplateTypeVOS, e));
				templateVOS.add(planTemplateVO);
			});

		} else {
			List<PlanTemplateVO> planCheckHistoryList = checkHistoryService.listPlanHistory(planId, tltId, templateId);
			planCheckHistoryList.forEach(e -> {
				e = disposePlanTemplateType(e, planId);
				e.setTemplateContentVOS(null);
			});
			templateVOS.addAll(planCheckHistoryList);
		}

		if (templateId == null && templateVOS.size() > 1) {
			//第一步创建一个全部的，将工作项合并一起
			PlanTemplateVO planTemplateVO = new PlanTemplateVO();
			planTemplateVO.setTemplateId(0L);
			planTemplateVO.setTemplateName("全部");
			List<PlanTemplateTypeVO> templateTypeVOS = new ArrayList<>(100);
			for (PlanTemplateVO planTemplateVO1 : templateVOS) {
				templateTypeVOS.addAll(planTemplateVO1.getTemplateTypeVOS());
			}

			//将工作项的位置分类进行分组合并
			List<Long> tltIds = templateTypeVOS.stream().map(PlanTemplateTypeVO::getTltId).distinct().collect(Collectors.toList());
			Map<Long, List<PlanTemplateTypeVO>> listMap = templateTypeVOS.stream().collect(Collectors.groupingBy(PlanTemplateTypeVO::getTltId));
			templateTypeVOS.clear();
			for (Long ttltId : tltIds) {
				PlanTemplateTypeVO resultPlanTemplateType = new PlanTemplateTypeVO();
				List<PlanTemplateContentVO> childrens = new ArrayList<>(16);
				List<PlanTemplateTypeVO> planTemplateTypeVOS = listMap.get(ttltId);
				PlanTemplateTypeVO planTemplateTypeVO = planTemplateTypeVOS.get(0);
				resultPlanTemplateType.setTltId(ttltId);
				resultPlanTemplateType.setTltName(planTemplateTypeVO.getTltName());
				if (planTemplateTypeVOS == null || planTemplateTypeVOS.size() == 0) {
					continue;
				}
				for (PlanTemplateTypeVO planTemplateTypeVO1 : planTemplateTypeVOS) {
					if (planTemplateTypeVO1.getPlanTemplateContentVOS() != null) {
						childrens.addAll(planTemplateTypeVO1.getPlanTemplateContentVOS());
					}
				}
				resultPlanTemplateType.setWorkItemCount(childrens.size());
				resultPlanTemplateType.setPlanTemplateContentVOS(childrens);
				templateTypeVOS.add(resultPlanTemplateType);
			}
			//只返回一个全部的
			planTemplateVO.setTemplateTypeVOS(templateTypeVOS);
			templateVOS.clear();
			templateVOS.add(planTemplateVO);
		}

		List<ByWorkScoreInfoVo> byWorkScoreInfo = planCheckHistoryScoreService.getByWorkScoreInfo(planId);
		Map<Long, List<ByWorkScoreInfoVo>> listMap = byWorkScoreInfo.stream().collect(Collectors.groupingBy(ByWorkScoreInfoVo::getCheckHistoryId));
		//新增评分信息
		for (PlanTemplateVO planTemplateVO : templateVOS) {
			List<PlanTemplateTypeVO> templateTypeVOS = planTemplateVO.getTemplateTypeVOS();
			for (PlanTemplateTypeVO planTemplateTypeVO : templateTypeVOS) {
				List<PlanTemplateContentVO> templateContentVOS = planTemplateTypeVO.getPlanTemplateContentVOS();
				if (templateContentVOS == null) {
					continue;
				}
				for (PlanTemplateContentVO planTemplateContentVO : templateContentVOS) {
					List<ByWorkScoreInfoVo> byWorkScoreInfoVos = listMap.get(planTemplateContentVO.getCheckHistoryId());
					if (byWorkScoreInfoVos != null && byWorkScoreInfoVos.size() > 0) {
						planTemplateContentVO.setByWorkScoreInfoVos(byWorkScoreInfoVos);
					}
				}
			}

		}
		return templateVOS;
	}

	/**
	 * 树形结构展示的某个节点的统计数值=所有子节点工作项数量总和
	 *
	 * @param root
	 * @param result
	 * @return
	 */
	public static PlanTemplateTypeVO doCount(PlanTemplateTypeVO root, Map<String, Object> result) {
		int count = 0;
		List<PlanTemplateTypeVO> list = root.getChildren();
		if (ObjectUtil.isEmpty(list)) {
			count = root.getPlanTemplateContentVOS().size();
			root.setWorkItemCount(count);
			return root;
		}

		for (PlanTemplateTypeVO child : list) {
			//统计子节点的孩子总数
			int cur_cnt = doCount(child, result).getWorkItemCount();
			result.put(String.valueOf(child.getTltId()), cur_cnt);
			count += cur_cnt;
			root.setWorkItemCount(count);
		}

		//返回前记录当前节点的统计个数
		result.put(String.valueOf(root.getTltId()), count);
		return root;
	}

	/**
	 * 树形结构展示的某个节点的统计数值=所有子节点工作项数量总和
	 *
	 * @param root
	 * @param result
	 * @param tltMap
	 * @return
	 */
	public static PlanDetailLocationTypeVO doTltCount(PlanDetailLocationTypeVO root, Map<String, Object> result, Map<Long, List<PlanDetailLocationTypeVO>> tltMap) {
		root.setTltId(root.getId());
		int count = 0;
		List<PlanDetailLocationTypeVO> list = root.getChildren();
		if (ObjectUtil.isEmpty(list)) {
			if (!tltMap.containsKey(root.getTltId())) {
				root.setWorkItemCount(count);
				return root;
			}
			count = tltMap.get(root.getTltId()).size();
			root.setWorkItemCount(count);
			return root;
		}

		for (PlanDetailLocationTypeVO child : list) {
			//统计子节点的孩子总数
			int cur_cnt = doTltCount(child, result, tltMap).getWorkItemCount();
			result.put(String.valueOf(child.getTltId()), cur_cnt);
			count += cur_cnt;
			root.setWorkItemCount(count);
		}

		//返回前记录当前节点的统计个数
		result.put(String.valueOf(root.getTltId()), count);
		return root;
	}

	/**
	 * 封装模板分类及对应工作项
	 *
	 * @param planTemplateVO
	 * @return
	 */
	private PlanTemplateVO disposePlanTemplateType(PlanTemplateVO planTemplateVO, Long planId) {
		List<PlanTemplateContentVO> templateContentVOS = planTemplateVO.getTemplateContentVOS();
		List<PlanTemplateTypeVO> templateTypeVOS = getTypeZeroList(templateContentVOS);
		for (PlanTemplateContentVO t : templateContentVOS) {
			// 封装模板分类Tree
			List<String> tltIds = Func.toStrList(t.getTltIds());
			List<String> tltIdName = Func.toStrList("&&", t.getTltNames());
			if (tltIds.size() > 1) {
				for (int i = 1; i < tltIds.size(); i++) {
					templateTypeVOS = changeHistory(templateTypeVOS, Long.valueOf(tltIds.get(i)), tltIdName.get(i), Long.valueOf(tltIds.get(i - 1)));
				}
			}
		}
		// 封装对应工作项
		templateTypeVOS = changeHistoryContent(templateTypeVOS, templateContentVOS);
		templateTypeVOS.forEach(e -> {
			e = doCount(e, new HashMap<>());
		});
		planTemplateVO.setTemplateTypeVOS(templateTypeVOS);
		return planTemplateVO;
	}

	/**
	 * 封装历史记录对应工作项
	 *
	 * @param templateTypeVOS 分类tree集合
	 * @return
	 */
	private List<PlanTemplateTypeVO> changeHistoryContent(List<PlanTemplateTypeVO> templateTypeVOS, List<PlanTemplateContentVO> templateContentVOS) {
		templateTypeVOS.forEach(e -> {
			if (ObjectUtil.isEmpty(e.getChildren())) {
				templateContentVOS.forEach(j -> {
					List<String> tltIds = Func.toStrList(j.getTltIds());
					if (e.getTltId().equals(Long.valueOf(tltIds.get(tltIds.size() - 1)))) {
						List<PlanTemplateContentVO> planTemplateContentVOS = e.getPlanTemplateContentVOS();
						if (ObjectUtil.isEmpty(planTemplateContentVOS)) {
							planTemplateContentVOS = new ArrayList<>();
						}
						planTemplateContentVOS.add(j);
						e.setPlanTemplateContentVOS(planTemplateContentVOS);
					}
				});
			} else {
				changeHistoryContent(e.getChildren(), templateContentVOS);
			}
		});
		return templateTypeVOS;
	}

	/**
	 * 封装任务历史数据分类Tree根节点
	 *
	 * @param templateContentVOS
	 * @return
	 */
	private List<PlanTemplateTypeVO> getTypeZeroList(List<PlanTemplateContentVO> templateContentVOS) {
		List<PlanTemplateTypeVO> planTemplateTypeVOS = templateContentVOS.stream().map(e -> {
			List<String> tltIds = Func.toStrList(e.getTltIds());
			List<String> tltIdName = Func.toStrList("&&", e.getTltNames());
			PlanTemplateTypeVO planTemplateTypeVO = new PlanTemplateTypeVO();
			planTemplateTypeVO.setTltId(Long.valueOf(tltIds.get(0)));
			planTemplateTypeVO.setTltName(tltIdName.get(0));
			planTemplateTypeVO.setTltParentId(0L);
			return planTemplateTypeVO;
		}).collect(Collectors.toList());
		planTemplateTypeVOS = planTemplateTypeVOS.stream().collect(Collectors.collectingAndThen(
			Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(e -> e.getTltId() + ";" + e.getTltName()))), ArrayList::new
		));
		return planTemplateTypeVOS;
	}

	/**
	 * 封装历史对应工作项分类数据
	 *
	 * @param planTemplateTypeVOS
	 * @param tltId
	 * @return
	 */
	private List<PlanTemplateTypeVO> changeHistory(List<PlanTemplateTypeVO> planTemplateTypeVOS, Long tltId, String tltName, Long parentId) {
		planTemplateTypeVOS.forEach(e -> {
			if (e.getTltId().equals(parentId)) {
				List<PlanTemplateTypeVO> children = e.getChildren();
				if (ObjectUtil.isEmpty(children)) {
					children = new ArrayList<>();
				}
				PlanTemplateTypeVO planTemplateTypeVO = new PlanTemplateTypeVO();
				planTemplateTypeVO.setTltId(tltId);
				planTemplateTypeVO.setTltName(tltName);
				planTemplateTypeVO.setTltParentId(parentId);
				children.add(planTemplateTypeVO);
				children = children.stream().collect(Collectors.collectingAndThen(
					Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(j -> j.getTltId() + ";" + j.getTltName()))), ArrayList::new
				));
				e.setChildren(children);
			} else {
				if (ObjectUtil.isNotEmpty(e.getChildren())) {
					changeHistory(e.getChildren(), tltId, tltName, parentId);
				}
			}
		});
		return planTemplateTypeVOS;
	}

	/**
	 * 递归模板分类Tree 封装对应工作项数据
	 *
	 * @param planTemplateTypeVOS
	 * @param templateId
	 * @return
	 */
	private List<PlanTemplateTypeVO> change(List<PlanTemplateTypeVO> planTemplateTypeVOS, Long templateId) {
		List<PlanTemplateContentVO> planTemplateContentVOS = baseMapper.selectPlanTemplateContent2(null, templateId);
		Map<Long, List<PlanTemplateContentVO>> planTemplateMap = planTemplateContentVOS.stream().collect(Collectors.groupingBy(t -> t.getTltId()));
		planTemplateTypeVOS.forEach(e -> {
			if (ObjectUtil.isEmpty(e.getChildren())) {
				e.setPlanTemplateContentVOS(planTemplateMap.get(e.getTltId()));
			} else {
				change(e.getChildren(), templateId);
			}
			e = doCount(e, new HashMap<>());
		});
		return planTemplateTypeVOS;
	}

	/**
	 * 获取模板下模板分类父级及其所有子节点
	 *
	 * @param tltId
	 * @param templateIds
	 * @return
	 */
	private List<Long> getTltIds(Long tltId, List<Long> templateIds) {
		List<TemplateLocationTypeTreeVO> typeTreeVOS = templateLocationTypeService.tree(tltId, templateIds);
		List<TemplateLocationTypeTreeVO> templateTltList = new ArrayList<>();
		templateTltList = change(templateTltList, typeTreeVOS);
		return templateTltList.stream().map(TemplateLocationTypeTreeVO::getTltId).collect(Collectors.toList());
	}

	/**
	 * 递归 分类树转集合
	 *
	 * @param templateTltList
	 * @param templateTltTreeList
	 * @return
	 */
	private List<TemplateLocationTypeTreeVO> change(List<TemplateLocationTypeTreeVO> templateTltList, List<TemplateLocationTypeTreeVO> templateTltTreeList) {
		templateTltTreeList.forEach(e -> {
			templateTltList.add(e);
			if (ObjectUtil.isNotEmpty(e.getChildren())) {
				change(templateTltList, e.getChildren());
			}
		});
		return templateTltList;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean planCommit(MaintainPlanContent entity) {

		MaintainPlanContent planContent = super.getById(entity.getId());
		if (!planContent.getStatus().equals(TaskStatusEnum.BY_PROCESSED.getStatus())) {
			throw new ServiceException("任务状态已更新，请刷新页面");
		}

//		int count = checkHistoryService.count(Wrappers.<MaintainCheckHistory>lambdaQuery().eq(MaintainCheckHistory::getPlanId, entity.getId()).isNull(MaintainCheckHistory::getResult));
//		if (count > 0) {
//			throw new ServiceException("工作项未全部完成，请继续完成作业");
//		}

		User user = userService.getById(AuthUtil.getUserId());

		// 系统代签 任务提交时 未签退人员自动签退
		signService.checkUserSignOut(entity.getId());

		MaintainPlanContent plan = new MaintainPlanContent();
		plan.setId(entity.getId());
		plan.setStatus(TaskStatusEnum.BY_FINISH.getStatus());
		this.update(plan);

		MaintainPlanContentExt planContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, planContent.getId()));
		planContentExt.setCommitTime(DateUtil.date());
		maintainPlanContentExtService.updateById(planContentExt);

		// 统计每个人上传的操作记录图片
//		countUserRecordImage(entity.getId());

		// 处理计划人与实际执行人
		planContentUserService.changePlanUser(entity.getId());

		// 插入任务记录
		PlanLogDTO planLogDTO = new PlanLogDTO();
		planLogDTO.setAddress(entity.getCommitAddress());
		planLogDTO.setLongitude(entity.getCommitLongitude());
		planLogDTO.setLatitude(entity.getCommitLatitude());
		malfunctionLogService.insertWorkLog(entity.getId(), WorkTrackStatusEnum.COMMIT.getTypeName(), TaskStatusEnum.BY_FINISH.getStatus(), JSONObject.toJSONString(planLogDTO), AuthUtil.getUserId(), user.getRealName());

		// 【保养完成】群消息
		ElevatorDetailVO elevatorDetailVO = elevatorService.selectElevatorDetail(planContent.getElevatorId());
		RobotContentDTO robotContentDTO = new RobotContentDTO();
		robotContentDTO.setMaintainType(MaintainPlanContentEnum.MAINTAIN_BY.getId());
		robotContentDTO.setMaintainSubTypeDesc("【保养完成通知】");
		StringBuilder locationDesc = new StringBuilder();
		locationDesc.append(elevatorDetailVO.getBuildingName()).append("-").append(elevatorDetailVO.getElevatorAddress());
		robotContentDTO.setLocationDesc(locationDesc.toString());
		robotContentDTO.setMaintainStatusDesc(TaskStatusEnum.getTaskName(MaintainPlanContentEnum.MAINTAIN_BY.getId(), plan.getStatus()));
		robotContentDTO.setElevatorStatusDesc(ElevatorStatusEnum.getName(elevatorDetailVO.getIsStop()));
		List<MaintainPlanContentUser> planUsers = planContentUserService.listUserByPlan(planContent.getId());
		robotContentDTO.setMaintainPersonDesc(planUsers.stream().map(t -> t.getUserName()).collect(Collectors.joining(",")));
		robotContentDTO.setMaintainPersonImgDesc(planUsers.stream().map(t -> t.getAvatar()).collect(Collectors.joining(",")));
		robotContentDTO.setMaintainImgUrl("https://erised.oss-cn-shenzhen.aliyuncs.com/img/202309041654060.jpg");
		robotUtil.sendRobotMessage(RequestContextHolder.getRequestAttributes(), planContent.getElevatorId(), planContent.getId(), robotContentDTO);

		return Boolean.TRUE;
	}

	/**
	 * 统计每个人上传的操作记录图片
	 *
	 * @param planId
	 */
	private void countUserRecordImage(Long planId) {
		List<MaintainPlanContentUser> planContentUsers = planContentUserService.list(Wrappers.<MaintainPlanContentUser>lambdaQuery().eq(MaintainPlanContentUser::getPlanId, planId));
		List<PlanCheckHistoryListDTO> checkHistoryList = checkHistoryService.getCheckHistoryList(planId);
		planContentUsers.forEach(e -> {
			final AtomicInteger imageNum = new AtomicInteger(0);
			checkHistoryList.forEach(j -> {
				if (ObjectUtil.isNotEmpty(j.getRecordVOList())) {
					if (j.getRecordData().getInteger("type").equals(2)) {
						List<CheckHistoryRecordVO> recordVOList = j.getRecordVOList().stream().peek(k -> k.setIndex(k.getRecordDataValue().getInteger("index"))).collect(Collectors.toList());
						Map<Integer, CheckHistoryRecordVO> recordMap = recordVOList.stream().collect(
							Collectors.groupingBy(CheckHistoryRecordVO::getIndex, Collectors.collectingAndThen(Collectors.reducing((t1, t2) -> t1.getUpdateTime().getTime() > t2.getUpdateTime().getTime() ? t1 : t2), Optional::get)));
						for (CheckHistoryRecordVO recordVO : recordMap.values()) {
							if (recordVO.getUserId().equals(e.getUserId())) {
								imageNum.set(imageNum.get() + j.getRecordVOList().get(0).getRecordDataValue().getJSONObject("files").getJSONArray("val").size());
							}
						}
					} else {
						if (e.getUserId().equals(j.getRecordVOList().get(0).getUserId())) {
							imageNum.set(imageNum.get() + j.getRecordVOList().get(0).getRecordDataValue().getJSONObject("files").getJSONArray("val").size());
						}
					}
				}
			});
			e.setImageNum(imageNum.get());
		});
		planContentUserService.updateBatchById(planContentUsers);
	}

	@Override
	public List<String> getLocationTypeOfplanId(Long planId) {
		return baseMapper.getLocationTypeOfplanId(planId);
	}

	@Override
	public List<Long> listUserPlan(Integer typeStatus, Long planId, Long userId) {
		return baseMapper.listUserPlan(typeStatus, planId, userId);
	}

	@Override
	public List<PlanTemplateContentVO> getPlanWorkItemList(Long planId) {
		MaintainPlanContent planContent = super.getById(planId);
		if (planContent.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())) {
			List<MaintainTemplate> planTemplates = planTemplateService.listPlanTemplate(planId);
			if (ObjectUtil.isEmpty(planTemplates)) {
				throw new ServiceException("工单排期类型已经变更，请重新排期!");
			}
			List<Long> templateIds = planTemplates.stream().map(MaintainTemplate::getId).collect(Collectors.toList());
			// 根据模板id集合获取任务所关联的模板及工作项
			List<PlanTemplateDTO> planTemplateDTOS = templateRelationService.listTemplateContent(templateIds, AuthUtil.getTenantId());
			if (ObjectUtil.isEmpty(planTemplateDTOS)) {
				throw new ServiceException("找不到对应工作项，请联系管理员!");
			}
			List<PlanTemplateContentVO> checkHistories = new ArrayList<>();
			planTemplateDTOS.forEach(e -> {
				e.getTemplateContentDTOS().forEach(j -> {
					HashMap<String, String> tltTreeStr = getTltTreeStr(e.getTemplateId(), j.getTltId());
					PlanTemplateContentVO checkHistory = new PlanTemplateContentVO();
					BeanUtil.copyProperties(j, checkHistory);
					checkHistory.setRequireDesc(j.getRequire());
					checkHistory.setPlanId(planId);
					checkHistory.setElevatorId(planContent.getElevatorId());
					checkHistory.setTemplateId(e.getTemplateId());
					checkHistory.setTemplateName(e.getTemplateName());
					checkHistory.setTemplateSceneTypeId(e.getSceneTypeId());
					checkHistory.setTemplateSceneTypeName(e.getSceneTypeName());
					checkHistory.setTltIds(tltTreeStr.get("tltIdTreeStr"));
					checkHistory.setTltNames(tltTreeStr.get("tltNameTreeStr"));
					checkHistories.add(checkHistory);
				});
			});
			return checkHistories;
		} else {
			return checkHistoryService.getPlanWorkItemList(planId);
		}
	}

	/**
	 * 处理模板分类冗余数据
	 *
	 * @param templateId
	 * @param tltId
	 * @return
	 */
	private HashMap<String, String> getTltTreeStr(Long templateId, Long tltId) {
		// 查询指定子节点所有父级 倒序
		List<TemplateLocationTypeTreeVO> templateTltTreeList = templateLocationTypeService.treeDesc(templateId, tltId);
		List<TemplateLocationTypeTreeVO> templateTltList = new ArrayList<>();
		templateTltList = change(templateTltList, templateTltTreeList);
		Collections.reverse(templateTltList);
		String tltIdTreeStr = templateTltList.stream().map(e -> String.valueOf(e.getTltId())).collect(Collectors.joining(","));
		String tltNameTreeStr = templateTltList.stream().map(TemplateLocationTypeTreeVO::getName).collect(Collectors.joining("&&"));
		HashMap<String, String> tltTreeStr = new HashMap<>(2);
		tltTreeStr.put("tltIdTreeStr", tltIdTreeStr);
		tltTreeStr.put("tltNameTreeStr", tltNameTreeStr);
		return tltTreeStr;
	}

	@Override
	public CheckPlanCountVO checkPlanCount(List<Long> userIds, String startTime, String endTime) {

		CheckPlanCountVO checkPlanCountVO = new CheckPlanCountVO();

		List<Long> planIds = baseMapper.selectPlanIdsByUsers(userIds, startTime, endTime, MaintainPlanContentEnum.MAINTAIN_BY.getId());
		planIds = planIds.stream().distinct().collect(Collectors.toList());

		int totalPlan = planIds.size();

		// 保养任务状态统计
		List<PlanCountVO> checkPlanStatusCountVOS;
		// 保养任务时长统计
		List<PlanCountVO> checkPlanDurationCountVO;
		// 保养时效性统计
		List<PlanCountVO> checkPlanTimelinessCountVO;
		// 保养任务签到统计
		List<PlanCountVO> checkPlanSignCountVO;
		if (ObjectUtil.isNotEmpty(planIds)) {

			checkPlanStatusCountVOS = baseMapper.countCheckPlanStatus(planIds);
			checkPlanStatusCountVOS.forEach(e -> {
				e.setPercentage(getPercentage(e.getValue(), totalPlan));
			});
			checkPlanCountVO.setCheckPlanStatusCountVOList(checkPlanStatusCountVOS);

			checkPlanDurationCountVO = baseMapper.countCheckPlanDuration(planIds);
			checkPlanDurationCountVO.forEach(e -> {
				e.setPercentage(getPercentage(e.getValue(), totalPlan));
			});
			checkPlanCountVO.setCheckPlanDurationCountVOList(checkPlanDurationCountVO);

			checkPlanTimelinessCountVO = baseMapper.countCheckPlanTimeliness(planIds);
			checkPlanTimelinessCountVO.forEach(e -> {
				e.setPercentage(getPercentage(e.getValue(), totalPlan));
			});
			checkPlanCountVO.setCheckPlanTimelinessCountVO(checkPlanTimelinessCountVO);

			int planSignTotal = signService.count(Wrappers.<MaintainSign>lambdaQuery().in(MaintainSign::getPlanId, planIds)) * 2;
			checkPlanSignCountVO = baseMapper.countCheckPlanSign(planIds, userIds);
			checkPlanSignCountVO.forEach(e -> {
				if (planSignTotal > 0) {
					e.setPercentage(getPercentage(e.getValue(), planSignTotal));
				} else {
					e.setPercentage(0);
				}
			});
			checkPlanCountVO.setCheckPlanSignCountVO(checkPlanSignCountVO);
		} else {

			checkPlanStatusCountVOS = TaskStatusEnum.getTaskStatusByType(MaintainPlanContentEnum.MAINTAIN_BY.getId()).stream().map(e -> {
				PlanCountVO planCountVO = new PlanCountVO();
				planCountVO.setName(e.getName());
				planCountVO.setValue(0);
				planCountVO.setPercentage(0);
				return planCountVO;
			}).collect(Collectors.toList());
			checkPlanCountVO.setCheckPlanStatusCountVOList(checkPlanStatusCountVOS);

			checkPlanDurationCountVO = Arrays.stream(PlanDurationEnum.values()).map(e -> {
				PlanCountVO planCountVO = new PlanCountVO();
				planCountVO.setName(e.getName());
				planCountVO.setValue(0);
				planCountVO.setPercentage(0);
				return planCountVO;
			}).collect(Collectors.toList());
			checkPlanCountVO.setCheckPlanDurationCountVOList(checkPlanDurationCountVO);

			checkPlanTimelinessCountVO = Arrays.stream(PlanTimelinessEnum.values()).map(e -> {
				PlanCountVO planCountVO = new PlanCountVO();
				planCountVO.setName(e.getName());
				planCountVO.setValue(0);
				planCountVO.setPercentage(0);
				return planCountVO;
			}).collect(Collectors.toList());
			checkPlanCountVO.setCheckPlanTimelinessCountVO(checkPlanTimelinessCountVO);

			checkPlanSignCountVO = Arrays.stream(PlanSignEnum.values()).map(e -> {
				PlanCountVO planCountVO = new PlanCountVO();
				planCountVO.setName(e.getName());
				planCountVO.setValue(0);
				planCountVO.setPercentage(0);
				return planCountVO;
			}).collect(Collectors.toList());
			checkPlanCountVO.setCheckPlanSignCountVO(checkPlanSignCountVO);

		}
		return checkPlanCountVO;
	}

	@Override
	public IPage<PlanDataPageVO> selectPlanList(CheckPlanPageQueryDTO queryDTO, IPage<PlanDataPageVO> page) {

		List<Long> planIds = baseMapper.selectPlanIdsByUsers(Func.toLongList(queryDTO.getUserIds()), queryDTO.getStartTime(), queryDTO.getEndTime(), MaintainPlanContentEnum.MAINTAIN_BY.getId());
		planIds = planIds.stream().distinct().collect(Collectors.toList());
		IPage<PlanDataPageVO> checkPageVOIPage;
		if (ObjectUtil.isNotEmpty(planIds)) {
			checkPageVOIPage = page.setRecords(baseMapper.selectPlanList(planIds, queryDTO, page));
			checkPageVOIPage = checkPageVOIPage.setRecords(changeCheckPageVO(checkPageVOIPage.getRecords()));
		} else {
			checkPageVOIPage = page.setRecords(new ArrayList<>());
		}
		return checkPageVOIPage;
	}

	@Override
	public IPage<PlanDataPageVO> selectScoreList(CheckPlanPageQueryDTO queryDTO, IPage<PlanDataPageVO> page) {
		IPage<PlanDataPageVO> scorePageVOIPage = page.setRecords(baseMapper.selectScoreList(Func.toLongList(queryDTO.getUserIds()), queryDTO.getStartTime(), queryDTO.getEndTime(), page));
		return scorePageVOIPage.setRecords(changeCheckPageVO(scorePageVOIPage.getRecords()));
	}

	/**
	 * 封装历史保养任务标签
	 *
	 * @param checkPageVOIPage
	 * @return
	 */
	private List<PlanDataPageVO> changeCheckPageVO(List<PlanDataPageVO> checkPageVOIPage) {
		if (Func.isEmpty(checkPageVOIPage)) {
			return checkPageVOIPage;
		}
		List<MaintainPlanContentUser> allPlanUsers = planContentUserService.listUserByPlanIds(checkPageVOIPage.stream().map(PlanDataPageVO::getPlanId).distinct().collect(Collectors.toList()));
		checkPageVOIPage.forEach(e -> {
			List<MaintainPlanContentUser> planContentUsers = allPlanUsers.stream().filter(t -> t.getPlanId().equals(e.getPlanId())).collect(Collectors.toList());
			// 封装状态描述
			e.setStatusDesc(TaskStatusEnum.getTaskName(e.getTypeStatus(), e.getStatus()));
			// 根据工单状态封装模板名称
			if (!e.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())) {
				// 封装关联人员签到状态，异常标签及过滤未工作人员
				planContentUsers = this.filterNotWorkUser(planContentUsers, e.getStatus(), e.getPlanId(), e.getTypeStatus());
			}
			// 封装关联人员组名称
			if (planContentUsers.size() > 0) {
				List<String> groupName = planContentUserService.listPlanUserDept(planContentUsers.stream().map(MaintainPlanContentUser::getUserId).collect(Collectors.toList()));
				e.setGroupNames(groupName.stream().distinct().collect(Collectors.toList()));
			}
			// 当前用户放在第一位
			e.setPlanContentUserVos(this.changeFirstUser(planContentUsers));
			// 根据工单状态封装及时性 时效性标签描述
			if (e.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus()) || e.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())) {

				if (e.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())) {
					if (Func.isNotEmpty(e.getWorkMinute())) {
						// 过长过短
						if (e.getWorkMinute() > 60) {
							e.setDuration(WorkTrackStatusEnum.TOO_LONG.getTypeName());
						} else if (e.getWorkMinute() < 25) {
							e.setDuration(WorkTrackStatusEnum.TOO_SHORT.getTypeName());
						}
					}
				}

				if (ObjectUtil.isNotEmpty(e.getMaintainSignatureTime())) {
					// 逾期
					if (e.getAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus()) && ObjectUtil.isNotEmpty(e.getPlanOverdueDate())) {
						long maintainSignatureTime = DateUtil.parse(DateUtil.format(e.getMaintainSignatureTime(), "yyyy-MM-dd")).getTime();
						long overdueDate = e.getPlanOverdueDate().getTime();
						if (maintainSignatureTime > overdueDate) {
							long betweenDay = DateUtil.between(e.getPlanOverdueDate(), e.getMaintainSignatureTime(), DateUnit.DAY);
							e.setOverdueName("逾期" + betweenDay + "天");
						}
					}


					// 及时超时
					long betweenDay = DateUtil.between(e.getPlanDate(), e.getMaintainSignatureTime(), DateUnit.DAY);
					if (betweenDay > 0) {
						if (e.getPlanDate().compareTo(e.getMaintainSignatureTime()) < 0) {
							e.setTimeliness("超时" + betweenDay + "天");
						}
					} else if (betweenDay == 0) {
						e.setTimeliness(WorkTrackStatusEnum.IN_TIME.getTypeName());
					}
				}
			} else {

				// 逾期
				if (e.getAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus()) && ObjectUtil.isNotEmpty(e.getElevatorOverdueDate())) {
					long nowDate = DateUtil.parse(DateUtil.today()).getTime();
					long planDate = e.getPlanDate().getTime();
					long overdueDate = e.getElevatorOverdueDate().getTime();
					if (planDate <= nowDate && nowDate > overdueDate) {
						long betweenDay = DateUtil.between(e.getElevatorOverdueDate(), DateUtil.date(), DateUnit.DAY);
						e.setOverdueName("逾期" + betweenDay + "天");
					}
				}
				// 及时超时
				long betweenDay = DateUtil.between(e.getPlanDate(), new Date(), DateUnit.DAY);
				if (betweenDay > 0) {
					if (e.getPlanDate().compareTo(DateUtil.date()) < 0) {
						e.setTimeliness("超时" + betweenDay + "天");
					}
				}
			}
		});
		return checkPageVOIPage;
	}

	@Override
	public Long selectCheckPlanCount(CheckPlanPageQueryDTO queryDTO) {
		List<Long> planIds = baseMapper.selectPlanIdsByUsers(Func.toLongList(queryDTO.getUserIds()), queryDTO.getStartTime(), queryDTO.getEndTime(), MaintainPlanContentEnum.MAINTAIN_BY.getId());
		planIds = planIds.stream().distinct().collect(Collectors.toList());
		if (ObjectUtil.isNotEmpty(planIds)) {
			return baseMapper.selectPlanCount(planIds, queryDTO);
		} else {
			return 0L;
		}
	}

	public Long selectMalPlanCount(CheckPlanPageQueryDTO queryDTO) {
		List<Long> planIds = baseMapper.selectPlanIdsByUsers(Func.toLongList(queryDTO.getUserIds()), queryDTO.getStartTime(), queryDTO.getEndTime(), MaintainPlanContentEnum.MAINTAIN_WX.getId());
		planIds = planIds.stream().distinct().collect(Collectors.toList());
		if (ObjectUtil.isNotEmpty(planIds)) {
			return baseMapper.selectMalPlanCount(planIds, queryDTO);
		} else {
			return 0L;
		}
	}

	@Override
	public Object elevatorPlanHistory(CheckPlanPageQueryDTO queryDTO, Query query) {
		HashMap<String, Object> resultMap = new HashMap<>(2);
		resultMap.put("checkCount", selectCheckPlanCount(queryDTO));
		resultMap.put("malCount", selectMalPlanCount(queryDTO));
		if (queryDTO.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_BY.getId())) {
			IPage<PlanDataPageVO> planCheckPage = selectPlanList(queryDTO, Condition.getPage(query));
			resultMap.put("list", planCheckPage);
		} else {
			resultMap.put("list", malfunctionPlanPage(queryDTO, Condition.getPage(query)));
		}

		return resultMap;
	}

	@Override
	public LastPlanVO selectElevatorLastPlan(Long elevatorId, Long planId) {
		LastPlanVO lastPlanVO = baseMapper.selectElevatorLastPlan(elevatorId, planId);
		if (Func.isEmpty(lastPlanVO)) {
			return lastPlanVO;
		}

		String desc = "";
		if (lastPlanVO.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_BY.getId())) {
			desc = this.getPlanTemplateName(lastPlanVO.getPlanId());
		} else if (lastPlanVO.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_WX.getId())) {
			desc = "故障维修";
		} else if (lastPlanVO.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_PARTS.getId())) {
			desc = MaintainPlanContentEnum.MAINTAIN_PARTS.getName();
		} else if (lastPlanVO.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_KR.getId())) {
			desc = MaintainPlanContentEnum.MAINTAIN_KR.getName();
		} else if (lastPlanVO.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_AFFAIR.getId())) {
			desc = MaintainPlanContentEnum.MAINTAIN_AFFAIR.getName();
		} else if (lastPlanVO.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_CHECK.getId())) {
			desc = MaintainPlanContentEnum.MAINTAIN_CHECK.getName();
		} else if (lastPlanVO.getTypeStatus().equals(MaintainPlanContentEnum.ABARBEITUNG.getId())) {
			desc = MaintainPlanContentEnum.ABARBEITUNG.getName();
		}
		lastPlanVO.setDesc(desc);
		lastPlanVO.setStatusName(TaskStatusEnum.getTaskName(lastPlanVO.getTypeStatus(), lastPlanVO.getStatus()));
		return lastPlanVO;
	}

	@Override
	public String getPlanTemplateName(Long planId) {
		return baseMapper.getPlanTemplateName(planId);
	}

	public IPage<MalFunctionPlanPageVO> malfunctionPlanPage(CheckPlanPageQueryDTO queryDTO, IPage<MalFunctionPlanPageVO> page) {
		List<Long> planIds = baseMapper.selectPlanIdsByUsers(Func.toLongList(queryDTO.getUserIds()), queryDTO.getStartTime(), queryDTO.getEndTime(), MaintainPlanContentEnum.MAINTAIN_WX.getId());
		planIds = planIds.stream().distinct().collect(Collectors.toList());
		if (ObjectUtil.isNotEmpty(planIds)) {
			return page.setRecords(baseMapper.selectMalFunctionPlanPage(planIds, queryDTO, page));
		} else {
			return page.setRecords(new ArrayList<>());
		}
	}

	/**
	 * 计算百分比返回整数
	 *
	 * @param num
	 * @param total
	 * @return
	 */
	private Integer getPercentage(Integer num, Integer total) {
		Double result = NumberUtil.div(Double.valueOf(num), Double.valueOf(total)) * 100;
		return result.intValue();
	}

	/**
	 * 获取维保完成的列表
	 *
	 * @param planContentSearchDTO 查询对象
	 * @return 数据集
	 */
	private List<MaintainPlanContentVo> getFinishList(PlanContentSearchDTO planContentSearchDTO, MaintainPlanContentHomeListVo maintainPlanContentHomeListVo) {
		List<Integer> statusList = new ArrayList<>(5);
		statusList.add(TaskStatusEnum.BY_SIGN.getStatus());
		planContentSearchDTO.setStatusList(statusList);

		List<MaintainPlanContentVo> list = new ArrayList<>();
		List<PlanContentElevatorVo> planContentElevatorVos2 = baseMapper.getFinishPlanList(planContentSearchDTO, AuthUtil.getTenantId());

		if (planContentSearchDTO.getTypeStatus() == null || planContentSearchDTO.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_KR.getId()) {
			List<PlanContentElevatorVo> rescueHomeList = getRescueHomeList(planContentSearchDTO, true);
			planContentElevatorVos2.addAll(rescueHomeList);
		}


//		//拼接配件的任务
//		PlanContentSearchDTO planContentSearchDTO2 = new PlanContentSearchDTO();
//		BeanUtil.copyProperties(planContentSearchDTO, planContentSearchDTO2);
//		List<Integer> statusList2 = new ArrayList<>(5);
//		statusList2.add(TaskStatusEnum.PARTS_FINISH.getStatus());
//		planContentSearchDTO2.setTypeStatus(MaintainPlanContentEnum.MAINTAIN_PARTS.getId());
//		planContentSearchDTO2.setStatusList(statusList2);
//		List<PlanContentElevatorVo> planContentElevatorVos3 = baseMapper.getFinishPlanList(planContentSearchDTO2, AuthUtil.getTenantId());
//		planContentElevatorVos2.addAll(planContentElevatorVos3);

		Integer finishCounts = maintainPlanContentHomeListVo.getFinishCounts();
		List<MaintainPlanContentListVo> maintainPlanContentListVos = new ArrayList<>(16);
		MaintainPlanContentVo maintainPlanContentVo = new MaintainPlanContentVo();
		List<Long> buildingIds = planContentElevatorVos2.stream().map(PlanContentElevatorVo::getBuildingId).distinct().collect(Collectors.toList());
		Map<Long, List<PlanContentElevatorVo>> collect = planContentElevatorVos2.stream().collect(Collectors.groupingBy(PlanContentElevatorVo::getBuildingId));
		Integer planDateCounts = 0;
		for (Long buildingId : buildingIds) {
			MaintainPlanContentListVo maintainPlanContentListVo = new MaintainPlanContentListVo();
			List<PlanContentElevatorVo> elevatorVoList1 = collect.get(buildingId);
			//剔除未参与工单的人员
			for (PlanContentElevatorVo planContentElevatorVo : elevatorVoList1) {
				planContentElevatorVo.setStatusName(getPlanStatusName(planContentElevatorVo));
				List<PlanUserSignDetailVo> signUsers = planContentElevatorVo.getSignUsers();
				List<PlanUserSignDetailVo> signUsers2 = new ArrayList<>(16);
				if (signUsers != null) {
					for (PlanUserSignDetailVo planUserSignDetailVo : signUsers) {
						if (planUserSignDetailVo.getIsTakePartIn()) {
							signUsers2.add(planUserSignDetailVo);
						}
					}
				}

				if (planContentElevatorVo.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_WX.getId()) {

					if (StrUtil.isNotEmpty(planContentElevatorVo.getProblemItem())) {
						List<String> ids = Arrays.asList(planContentElevatorVo.getProblemItem().split(","));
						List<Dict> dicts = dictService.list(Wrappers.<Dict>lambdaQuery().eq(Dict::getCode, "fault_problem").in(Dict::getDictKey, ids));
						if (dicts.size() > 0) {
							List<String> strings = dicts.stream().map(Dict::getDictValue).collect(Collectors.toList());
							planContentElevatorVo.setProblemItemNames(strings);
						}
					}
				} else if (planContentElevatorVo.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_BY.getId() && planContentElevatorVo.getAuditType().equals(AUDIT_TYPE[2])) {
					if (planContentElevatorVo.getMaintainSignatureTime() != null && planContentElevatorVo.getOverdueDate() != null) {
						if (planContentElevatorVo.getMaintainSignatureTime().after(planContentElevatorVo.getOverdueDate())) {
							planContentElevatorVo.setTimeliness("逾期" + DateUtil.betweenDay(planContentElevatorVo.getMaintainSignatureTime(), planContentElevatorVo.getOverdueDate(), true) + "天");
						}
					}
				}
				planContentElevatorVo.setSignUsers(signUsers2);
			}

			PlanContentElevatorVo planContentElevatorVo = elevatorVoList1.get(0);
			BeanUtil.copyProperties(planContentElevatorVo, maintainPlanContentListVo);
			maintainPlanContentListVo.setBuildingName(maintainPlanContentListVo.getBuildingName());
			maintainPlanContentListVo.setList(elevatorVoList1);
			maintainPlanContentListVos.add(maintainPlanContentListVo);
			finishCounts = finishCounts + elevatorVoList1.size();
		}
		if (maintainPlanContentListVos.size() > 0) {
			maintainPlanContentVo.setMaintainPlanContentListVos(maintainPlanContentListVos);
			list.add(maintainPlanContentVo);
		}
		maintainPlanContentHomeListVo.setFinishCounts(finishCounts);
		return list;
	}

	private List<MaintainPlanContentTypeCountVo> getplanContentType(PlanContentSearchDTO planContentSearchDTO) {

		return baseMapper.getplanContentType(planContentSearchDTO);
	}


	private String getPlanStatusName(PlanContentElevatorVo planContentElevatorVo) {
		return TaskStatusEnum.getTaskName(planContentElevatorVo.getTypeStatus(), planContentElevatorVo.getStatus());
	}


	@Override
	public ElevatorSimpleInfoVO getElevatorSimpleInfo(Long planId) {
		return baseMapper.getElevatorSimpleInfo(planId);
	}

	@Override
	public int countCorrelationPlan(Long planId) {
		return baseMapper.countCorrelationPlan(planId);
	}

	@Override
	public MaintainPlanContent getMaintainPlanByProcessInstanceId(String processInstanceId) {
		return baseMapper.selectOne(Wrappers.<MaintainPlanContent>lambdaQuery().eq(MaintainPlanContent::getProcessInstanceId, processInstanceId));
	}

	@Override
	public Object allElevatorPlanHistory(CheckPlanPageQueryDTO queryDTO, IPage<Object> page) {
		HashMap<String, Object> resultMap = new HashMap<>(4);
		resultMap.putAll(baseMapper.countElevatorPlan(queryDTO));
		if (queryDTO.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_BY.getId())) {
			IPage<PlanDataPageVO> planCheckPage = baseMapper.selectElevatorCheckPlanList(queryDTO, page);
			planCheckPage.setRecords(this.changeCheckPageVO(planCheckPage.getRecords()));
			resultMap.put("list", planCheckPage);
		} else if (queryDTO.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_WX.getId())) {
			resultMap.put("list", baseMapper.selectElevatorMalfunctionPlanList(queryDTO, page));
		} else if (queryDTO.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_PARTS.getId())) {
			resultMap.put("list", baseMapper.selectElevatorPartsPlanList(queryDTO, page));
		}
		return resultMap;
	}


	/**
	 * 判断工单是否逾期
	 *
	 * @param planDate yyyy-MM-dd
	 * @param date     yyyy-MM-dd
	 * @return
	 */
	public static boolean afterDate(String planDate, String date) {
		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		//把String转为LocalDate
		LocalDate a = LocalDate.parse(planDate, dtf);
		LocalDate b = LocalDate.parse(date, dtf);
		//判断指定日期是否大于计划日期
		return b.isAfter(a);
	}

	@Override
	public HomePlanStatusCountVO selectUserPlanStatus(Long userId) {
		HomePlanStatusCountVO result = new HomePlanStatusCountVO();
		result.setToStart(baseMapper.selectUserPlanStatusToStart(userId));
		result.setUnderway(baseMapper.selectUserPlanStatusUnderway(userId));
		result.setFinished(baseMapper.selectUserPlanStatusFinished(userId));
		return result;
	}

	@Override
	public HomePlanApproveCountVO selectUserPlanApprove(Long userId) {
		return baseMapper.selectUserPlanApprove(userId);
	}

	@Override
	public HomePlanApplyCountVO selectUserPlanApply(Long userId) {

//		BladeFlow bladeFlow = new BladeFlow();
//		bladeFlow.setProcessDefinitionKey(ProcessConstant.PARTS);
//		bladeFlow.setTaskName(String.format("%s,%s", PartsApproveRoleEnum.GROUP.getTaskName(), PartsApproveRoleEnum.MANAGER.getTaskName()));
//		List<BladeFlow> todoList = flowBusinessService.selectTodoList(bladeFlow);
//		List<BladeFlow> doneList = flowBusinessService.selectDoneList(bladeFlow);
		HomePlanApplyCountVO result = baseMapper.selectUserPlanApply(userId);
//		result.setPending(result.getPending() + todoList.size());
//		result.setProcessed(result.getProcessed() + doneList.size());
		return result;
	}

	@Override
	public HomeDeptBuildingPlanCountVO selectDeptBuildingPlanCount(Long userId) {

		HomeDeptBuildingPlanCountVO result = new HomeDeptBuildingPlanCountVO();

		String deptIds = AuthUtil.getDeptId();
		List<String> deptIdList = new ArrayList<>();
		if (ObjectUtil.isNotEmpty(deptIds)) {
			deptIdList = Func.toStrList(deptIds);
		}
		if (!deptIdList.isEmpty()) {
			List<Long> userDeptList = deptService.listChildByParentId(deptIdList.get(0));
			List<Long> userIds = userService.listUserByDeptIds(userDeptList);
			result = baseMapper.countPlanByUser(userIds);
			HomeDeptBuildingPlanCountVO buildingResult = baseMapper.countBuildingByUser(null);
			result.setBuilding(buildingResult.getBuilding());
			result.setElevator(buildingResult.getElevator());
			result.setDeptName(deptService.getById(Long.valueOf(deptIdList.get(0))).getDeptName());
		} else {
			result.setBuilding(0);
			result.setElevator(0);
			result.setAllPlan(0);
			result.setFinishPlan(0);
		}
		return result;
	}

	@Override
	public HomeDeptBuildingPlanCountVO selectUserBuildingPlanCount(Long userId) {

		List<Long> userIds = new ArrayList<>();
		userIds.add(AuthUtil.getUserId());
		HomeDeptBuildingPlanCountVO result = baseMapper.countPlanByUser(userIds);
		HomeDeptBuildingPlanCountVO buildingResult = baseMapper.countBuildingByUser(userIds);
		result.setBuilding(buildingResult.getBuilding());
		result.setElevator(buildingResult.getElevator());
		return result;
	}

	@Override
	public IPage<PlanDataPageVO> elevatorPlanHistoryBy(ByPlanHistoryDTO queryDTO, IPage<PlanDataPageVO> page) {
		queryDTO.setTenantId(AuthUtil.getTenantId());
		queryDTO.setSelfId(AuthUtil.getUserId());
		IPage<PlanDataPageVO> planCheckPage = baseMapper.elevatorPlanHistoryBy(queryDTO, page);
		planCheckPage.setRecords(this.changeCheckPageVO(planCheckPage.getRecords()));
		return planCheckPage;
	}

	@Override
	public IPage<MalFunctionPlanPageVO> elevatorPlanHistoryWx(WxPlanHistoryDTO queryDTO, IPage<MalFunctionPlanPageVO> page) {
		IPage<MalFunctionPlanPageVO> pageList = baseMapper.elevatorPlanHistoryWx(queryDTO, page);
		pageList.getRecords().forEach(e -> {
			if (Func.isNotBlank(e.getProblemItem())) {
				List<String> problemKeys = Func.toStrList(e.getProblemItem());
				List<String> problemNames = new ArrayList<>();
				for (String problemKey : problemKeys) {
					String problemName = DictCache.getValue("fault_problem", problemKey);
					problemNames.add(problemName);
				}
				e.setProblemItemNames(problemNames);
				if (ObjectUtil.isNotEmpty(e.getPlanContentUserVos())) {
					e.setPlanContentUserVos(this.filterNotWorkUser(e.getPlanContentUserVos(), e.getStatus(), e.getPlanId(), e.getTypeStatus()));
					e.setPlanContentUserVos(this.changeFirstUser(e.getPlanContentUserVos()));
				}
			}
		});
		return pageList;
	}

	/**
	 * 封装关联人员签到状态，异常标签及过滤未工作人员
	 *
	 * @param users      人员列表
	 * @param planStatus 工单状态
	 * @param planId     工单id
	 * @return
	 */
	private List<MaintainPlanContentUser> filterNotWorkUser(List<MaintainPlanContentUser> users, Integer planStatus, Long planId, Integer typeStatus) {
		users = users.stream().filter(j -> {
			// 统计人员签到次数，签到签退异常次数
			PlanUserSignCountDTO userSignCount = signService.countUserSignError(planId, j.getUserId());
			// 过滤未工作人员
			if (typeStatus.equals(MaintainPlanContentEnum.MAINTAIN_BY.getId()) && !planStatus.equals(TaskStatusEnum.BY_PROCESSED.getStatus())) {
				if (userSignCount.getSignCount() <= 0) {
					return false;
				}
			} else if (typeStatus.equals(MaintainPlanContentEnum.MAINTAIN_WX.getId()) && planStatus.equals(TaskStatusEnum.WX_SIGN_FINISH.getStatus())) {
				if (userSignCount.getSignCount() <= 0) {
					return false;
				}
			} else if (typeStatus.equals(MaintainPlanContentEnum.MAINTAIN_PARTS.getId()) && planStatus.equals(TaskStatusEnum.PARTS_FINISH.getStatus())) {
				if (userSignCount.getSignCount() <= 0) {
					return false;
				}
			}
			// 封装签到异常标签
			List<String> signDesc = new ArrayList<>();
			if (userSignCount.getSignError() > 0) {
				signDesc.add(WorkTrackStatusEnum.SIGN.getTypeName() + WorkTrackStatusEnum.ADDRESS_ERROR.getTypeName());
			}
			if (userSignCount.getSignOutError() > 0) {
				signDesc.add(WorkTrackStatusEnum.SIGN_OUT.getTypeName() + WorkTrackStatusEnum.ADDRESS_ERROR.getTypeName());
			}
			j.setSignDesc(signDesc);
			return true;
		}).collect(Collectors.toList());
		return users;
	}

	/**
	 * 修改用户列表第一位为当前登录用户
	 *
	 * @param users 人员列表
	 * @return
	 */
	private List<MaintainPlanContentUser> changeFirstUser(List<MaintainPlanContentUser> users) {
		int index = IntStream.range(0, users.size()).filter(i -> users.get(i).getUserId().equals(AuthUtil.getUserId())).findFirst().orElse(-1);
		if (index != -1) {
			Collections.swap(users, index, 0);
		}
		return users;
	}

	@Override
	public IPage<MalFunctionPlanPageVO> elevatorPlanHistoryPj(PjPlanHistoryDTO queryDTO, IPage<MalFunctionPlanPageVO> page) {
		IPage<MalFunctionPlanPageVO> pageList = baseMapper.elevatorPlanHistoryPj(queryDTO, page);
		pageList.getRecords().forEach(e -> {
			if (ObjectUtil.isNotEmpty(e.getPlanContentUserVos())) {
				e.setPlanContentUserVos(this.filterNotWorkUser(e.getPlanContentUserVos(), e.getStatus(), e.getPlanId(), e.getTypeStatus()));
				e.setPlanContentUserVos(this.changeFirstUser(e.getPlanContentUserVos()));
			}
			if (!Func.isNull(e.getElevatorId())) {
				Integer isStop = elevatorService.selectElevatorDetail(e.getElevatorId()).getIsStop();
				e.setIsStop(isStop);
			}
		});
		return pageList;
	}

	@Override
	public Map<String, Object> elevatorPlanHistoryFinishBy(ByPlanHistoryDTO queryDTO) {
		Map<String, Object> resultMap = new HashMap<>(2);
		List<PlanDatePageVO> planCheckPage = baseMapper.elevatorPlanHistoryFinishBy(queryDTO, AuthUtil.getTenantId());
		final PlanConfigVo planConfigVo = maintainPlanConfigService.getPlanConfigVo(queryDTO.getElevatorId());

		AtomicInteger total = new AtomicInteger();
		if (ObjectUtil.isNotEmpty(planCheckPage)) {
			planCheckPage.forEach(j -> {
				total.addAndGet(j.getDataList().size());
				j.setDataList(this.changeCheckPageVO(j.getDataList()));
			});
		}
		resultMap.put("title", String.format("已保养(%d)", total.get()));
		resultMap.put("total", total.get());
		resultMap.put("list", planCheckPage);
		if (planConfigVo != null) {
			resultMap.put("auditType", planConfigVo.getAuditType());
		}

		return resultMap;
	}

	@Override
	public Map<String, Object> elevatorPlanHistoryUnfinishedBy(ByPlanHistoryDTO queryDTO) {
		Map<String, Object> resultMap = new HashMap<>(2);
		List<PlanDatePageVO> planCheckPage = baseMapper.elevatorPlanHistoryUnfinishedBy(queryDTO, AuthUtil.getTenantId());
		if (ObjectUtil.isNotEmpty(planCheckPage)) {
			planCheckPage.forEach(j -> j.setDataList(this.changeCheckPageVO(j.getDataList())));
		}
		resultMap.put("title", "仅显示未完成保养任务及未来半年内保养计划");
		resultMap.put("list", planCheckPage);
		return resultMap;
	}

	@Override
	public Map<String, Object> elevatorPlanHistoryFinishWx(WxPlanHistoryDTO queryDTO) {
		Map<String, Object> resultMap = new HashMap<>(2);
		List<PlanDatePageVO> planCheckPage = baseMapper.elevatorPlanHistoryFinishWx(queryDTO);
		AtomicInteger total = new AtomicInteger();
		if (ObjectUtil.isNotEmpty(planCheckPage)) {
			planCheckPage.forEach(j -> {
				total.addAndGet(j.getDataList().size());
				j.getDataList().forEach(e -> {
					List<String> problemNames = new ArrayList<>();
					if (Func.isNotBlank(e.getProblemItem())) {
						List<String> problemKeys = Func.toStrList(e.getProblemItem());
						for (String problemKey : problemKeys) {
							String problemName = DictCache.getValue("fault_problem", problemKey);
							problemNames.add(problemName);
						}
					}
					if (Func.isNotBlank(e.getProblemOtherDesc())) {
						problemNames.add(e.getProblemOtherDesc());
					}
					e.setProblemItemNames(problemNames);
					e.setPlanContentUserVos(this.filterNotWorkUser(e.getPlanContentUserVos(), e.getStatus(), e.getPlanId(), e.getTypeStatus()));
				});
			});
		}
		resultMap.put("title", String.format("已完成维修(%d)", total.get()));
		resultMap.put("total", total.get());
		resultMap.put("list", planCheckPage);
		return resultMap;
	}

	@Override
	public Map<String, Object> elevatorPlanHistoryUnfinishedWx(WxPlanHistoryDTO queryDTO) {
		Map<String, Object> resultMap = new HashMap<>(2);
		List<PlanDatePageVO> planCheckPage = baseMapper.elevatorPlanHistoryUnfinishedWx(queryDTO);
		if (ObjectUtil.isNotEmpty(planCheckPage)) {
			planCheckPage.forEach(j -> {
				j.getDataList().forEach(e -> {
					List<String> problemNames = new ArrayList<>();
					if (Func.isNotBlank(e.getProblemItem())) {
						List<String> problemKeys = Func.toStrList(e.getProblemItem());
						for (String problemKey : problemKeys) {
							String problemName = DictCache.getValue("fault_problem", problemKey);
							problemNames.add(problemName);
						}
					}
					if (Func.isNotBlank(e.getProblemOtherDesc())) {
						problemNames.add(e.getProblemOtherDesc());
					}
					e.setProblemItemNames(problemNames);
				});
			});
		}
		resultMap.put("title", "仅显示未完成的维修任务");
		resultMap.put("list", planCheckPage);
		return resultMap;
	}

	@Override
	public Map<String, Object> elevatorPlanHistoryFinishPj(PjPlanHistoryDTO queryDTO) {
		Map<String, Object> resultMap = new HashMap<>(2);
		List<PlanDatePageVO> planCheckPage = baseMapper.elevatorPlanHistoryFinishPj(queryDTO);
		AtomicInteger total = new AtomicInteger();
		planCheckPage.forEach(j -> {
			total.addAndGet(j.getDataList().size());
			j.getDataList().forEach(e -> e.setPlanContentUserVos(this.filterNotWorkUser(e.getPlanContentUserVos(), e.getStatus(), e.getPlanId(), e.getTypeStatus())));
		});
		resultMap.put("title", String.format("已完成配件更换(%d)", total.get()));
		resultMap.put("total", total.get());
		resultMap.put("list", planCheckPage);
		return resultMap;
	}

	@Override
	public Map<String, Object> elevatorPlanHistoryUnfinishedPj(PjPlanHistoryDTO queryDTO) {
		Map<String, Object> resultMap = new HashMap<>(2);
		List<PlanDatePageVO> planCheckPage = baseMapper.elevatorPlanHistoryUnfinishedPj(queryDTO);
		resultMap.put("title", "仅显示未完成的配件任务");
		resultMap.put("list", planCheckPage);
		return resultMap;
	}

	@Override
	public SimpleElevatorPlanInfoDTO getSimpleElevatorPlanInfo(Long planId) {
		return baseMapper.getSimpleElevatorPlanInfo(planId);
	}


	@Override
	public Map<String, List<PlanUserInfoVo>> getPlanUserInfo(Long planId) {

		List<PlanUserInfoVo> planUserInfoVos = new ArrayList<>(16);
		final List<MaintainPlanContentUser> maintainPlanContentUsers = planContentUserService.list(Wrappers.<MaintainPlanContentUser>lambdaQuery().eq(MaintainPlanContentUser::getPlanId, planId));
		final Map<Long, List<MaintainPlanContentUser>> map = maintainPlanContentUsers.stream().collect(Collectors.groupingBy(MaintainPlanContentUser::getUserId));

		final List<Long> userIds = maintainPlanContentUsers.stream().map(MaintainPlanContentUser::getUserId).collect(Collectors.toList());
		final List<UserVO> userList = userService.getUserList(userIds);
		for (UserVO userVO : userList) {
			PlanUserInfoVo planUserInfoVo = new PlanUserInfoVo();
			planUserInfoVo.setUserName(userVO.getRealName());
			planUserInfoVo.setDeptName(userVO.getDeptName());
			MaintainPlanContentUser maintainPlanContentUser = map.get(userVO.getId()).get(0);
			if (StrUtil.isNotEmpty(maintainPlanContentUser.getSignInfo())) {
				PlanUserSignDetailVo signUser = maintainPlanContentUser.getSignUser();
				planUserInfoVo.setIsPlanStatus(signUser.getIsPlanStatus());
				planUserInfoVo.setIsTakePartIn(signUser.getIsTakePartIn());
			}
			String signStatusInfo = maintainPlanContentUser.getSignStatusInfo();
			if (StrUtil.isNotEmpty(signStatusInfo)) {
				SignStatusInfoVo signStatusInfoVo = JSON.parseObject(signStatusInfo, SignStatusInfoVo.class);
				planUserInfoVo.setSignStatus(signStatusInfoVo.getSignStatus());
				planUserInfoVo.setSignOutStatus(signStatusInfoVo.getSignOutStatus());
			}
			planUserInfoVos.add(planUserInfoVo);
		}
		Map<String, List<PlanUserInfoVo>> listMap = planUserInfoVos.stream().collect(Collectors.groupingBy(PlanUserInfoVo::getDeptName));
		return listMap;
	}

	//	@Async
	@Override
	public void sendEstateMsg(Long planId) {
		// 根据电梯年审非年审查询安全员或管理员
		SimpleElevatorPlanInfoDTO infoDTO = this.getSimpleElevatorPlanInfo(planId);
		List<SimpleUserVO> simpleUserVOS = userService.getSimpleUserInfoByElevatorUseType(infoDTO.getElevatorId(), infoDTO.getUseType());
		// 查不到直接发送到对应物业租户 admin 角色下所有人
		if (org.springblade.core.tool.utils.ObjectUtil.isEmpty(simpleUserVOS)) {
			simpleUserVOS = userService.getAdminInfoByTenant(infoDTO.getTenantId());
		}
		simpleUserVOS.forEach(e -> {
			if (ObjectUtil.isNotEmpty(e.getOpenid())) {
				HashMap<String, Object> map = new HashMap<>(3);
				HashMap<String, String> templateMap = new HashMap<>(5);
				templateMap.put("first", "您有一个" + MaintainPlanContentEnum.getName(infoDTO.getTypeStatus()) + "工单需要确认签字，请您及时处理！");
				templateMap.put("keyword1", MaintainPlanContentEnum.getName(infoDTO.getTypeStatus()));
				templateMap.put("keyword2", infoDTO.getBuildingName() + infoDTO.getElevatorAddress());
				templateMap.put("keyword3", DateUtil.now());
				templateMap.put("keyword4", infoDTO.getUserName());
				templateMap.put("keyword5", infoDTO.getTenantName());
				templateMap.put("remark", "请您及时处理！");
				templateMap.put("params", "pages/toDoList/index");
				map.put("sendType", sendType);
				map.put("openid", e.getOpenid());
				map.put("params", templateMap);
				map.put("templateId", TemplateMsgConstant.TWY_ELEVATOR_SAFE_SIGN_ID);
				HttpUtil.createPost(estateApiUrl + official_accounts_push_url).body(JSONObject.toJSONString(map)).execute().body();
			}
			if (ObjectUtil.isNotEmpty(e.getPhone())) {
				HashMap<String, Object> map = new HashMap<>(3);
				HashMap<String, String> smsMap = new HashMap<>(5);
				smsMap.put("statusName", "待签字");
				map.put("phone", e.getPhone());
				map.put("params", smsMap);
				map.put("smsCode", estate_sms_code);
				HttpUtil.createPost(estateApiUrl + note_push_url).body(JSONObject.toJSONString(map)).execute().body();
			}
		});
	}

	@Override
	public Map<String, Object> selectPlanSimpleDetail(Long planId) {
		Map<String, Object> planSimpleDetail = new HashMap<>();
		MaintainPlanContent planContent = super.getById(planId);
		Map<String, Object> lastPlanSimpleDetail = baseMapper.selectPlanSimpleDetailByElevator(planContent.getElevatorId(), planContent.getPlanDate());
		planSimpleDetail.put("planId", planContent.getId());
		planSimpleDetail.put("planDate", planContent.getPlanDate());
		if (ObjectUtil.isNotEmpty(lastPlanSimpleDetail)) {
			planSimpleDetail.put("lastPlanId", lastPlanSimpleDetail.get("planId"));
			planSimpleDetail.put("lastPlanDate", lastPlanSimpleDetail.get("signatureDate"));
		}
		return planSimpleDetail;
	}

	@Override
	public List<MaintainPlanContent> listByUserDate(PlanCheckStatisticsQueryDTO queryDTO, List<Long> userIds) {
		return baseMapper.listByUserDate(queryDTO, userIds);
	}

	@Override
	public List<CheckStatisticsPlanSimpleDTO> listPlanExtByUserDate(PlanCheckStatisticsQueryDTO queryDTO, List<Long> userIds) {
		return baseMapper.listPlanExtByUserDate(queryDTO, userIds);
	}

	@Override
	public List<PlanTypeStatisticVo> getPlanTypeStatistic() {
		List<PlanTypeStatisticVo> planTypeStatisticVos = new ArrayList<>(3);
		PlanTypeStatisticVo byModel = new PlanTypeStatisticVo();
		PlanTypeStatisticVo wxModel = new PlanTypeStatisticVo();
		PlanTypeStatisticVo pjModel = new PlanTypeStatisticVo();
		PlanTypeStatisticVo swModel = new PlanTypeStatisticVo();
		PlanTypeStatisticVo zjModel = new PlanTypeStatisticVo();
		PlanTypeStatisticVo zgModel = new PlanTypeStatisticVo();

		Date endDate = new Date();
		DateTime beginTime = DateUtil.offsetDay(endDate, -365);
		Long userId = AuthUtil.getUserId();
		List<MaintainPlanContent> list = baseMapper.getPlanTypeStatistic(beginTime, endDate, userId, AuthUtil.getTenantId());
		List<MaintainPlanContent> byList = list.stream().filter(o -> o.getStatus() == TaskStatusEnum.BY_PROCESSED.getStatus() && o.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_BY.getId()).collect(Collectors.toList());
		List<MaintainPlanContent> wxList = list.stream().filter(o -> o.getStatus() == TaskStatusEnum.WX_UNDER_WAY.getStatus() && o.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_WX.getId()).collect(Collectors.toList());
		List<MaintainPlanContent> pjList = list.stream().filter(o -> o.getStatus() == TaskStatusEnum.PARTS_CHANGE.getStatus() && o.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_PARTS.getId()).collect(Collectors.toList());
		List<MaintainPlanContent> swList = list.stream().filter(o -> o.getStatus() == TaskStatusEnum.SW_UNDER_WAY.getStatus() && o.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_AFFAIR.getId()).collect(Collectors.toList());
		List<MaintainPlanContent> zjList = list.stream().filter(o -> o.getStatus() == TaskStatusEnum.ZJ_UNDER_WAY.getStatus() && o.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_CHECK.getId()).collect(Collectors.toList());
		List<MaintainPlanContent> zgList = list.stream().filter(o -> o.getStatus() == TaskStatusEnum.ZG_UNDER_WAY.getStatus() && o.getTypeStatus() == MaintainPlanContentEnum.ABARBEITUNG.getId()).collect(Collectors.toList());

		if (byList.size() > 0) {
			byModel.setPlanType(MaintainPlanContentEnum.MAINTAIN_BY.getId());
			byModel.setPlanCounts(byList.size());
			byModel.setPlanDetailVos(planDetailInit(byList));
			planTypeStatisticVos.add(byModel);
		}

		if (wxList.size() > 0) {
			wxModel.setPlanType(MaintainPlanContentEnum.MAINTAIN_WX.getId());
			wxModel.setPlanCounts(wxList.size());
			wxModel.setPlanDetailVos(planDetailInit(wxList));
			planTypeStatisticVos.add(wxModel);
		}

		if (pjList.size() > 0) {
			pjModel.setPlanType(MaintainPlanContentEnum.MAINTAIN_PARTS.getId());
			pjModel.setPlanCounts(pjList.size());
			pjModel.setPlanDetailVos(planDetailInit(pjList));
			planTypeStatisticVos.add(pjModel);
		}

		//2023-03-01新增救援的返回
		List<MaintainPlanContent> jyList = list.stream().filter(o -> (o.getStatus() == TaskStatusEnum.JY_TO_START.getStatus() || o.getStatus() == TaskStatusEnum.JY_PROCESSED.getStatus() || o.getStatus() == TaskStatusEnum.JY_ARRIVE.getStatus()) && o.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_KR.getId()).collect(Collectors.toList());
		PlanTypeStatisticVo jyModel = new PlanTypeStatisticVo();

		if (jyList.size() > 0) {
			jyModel.setPlanType(MaintainPlanContentEnum.MAINTAIN_KR.getId());
			jyModel.setPlanCounts(jyList.size());
			jyModel.setPlanDetailVos(planDetailInit(jyList));
			planTypeStatisticVos.add(jyModel);
		}

		//2023-12-14 新增质检和事务进行中的工单
		if (swList.size() > 0) {
			swModel.setPlanType(MaintainPlanContentEnum.MAINTAIN_AFFAIR.getId());
			swModel.setPlanCounts(swList.size());
			swModel.setPlanDetailVos(planDetailInit(swList));
			planTypeStatisticVos.add(swModel);
		}

		if (zjList.size() > 0) {
			zjModel.setPlanType(MaintainPlanContentEnum.MAINTAIN_CHECK.getId());
			zjModel.setPlanCounts(zjList.size());
			zjModel.setPlanDetailVos(planDetailInit(zjList));
			planTypeStatisticVos.add(zjModel);
		}

		if (zgList.size() > 0) {
			zgModel.setPlanType(MaintainPlanContentEnum.ABARBEITUNG.getId());
			zgModel.setPlanCounts(zgList.size());
			zgModel.setPlanDetailVos(planDetailInit(zgList));
			planTypeStatisticVos.add(zgModel);
		}
		return planTypeStatisticVos;
	}


	/**
	 * 用于获取进行中工单的数据转换
	 *
	 * @param list 工单列表
	 * @return 数据集
	 */
	private List<PlanDetailVo> planDetailInit(List<MaintainPlanContent> list) {
		List<PlanDetailVo> resultList = new ArrayList<>();
		for (MaintainPlanContent content : list) {
			PlanDetailVo planDetailVo = new PlanDetailVo();
			planDetailVo.setPlanId(content.getId());
			planDetailVo.setElevatorId(content.getElevatorId());
			planDetailVo.setPlanCheckName(content.getPlanCheckName());
			planDetailVo.setPlanDate(content.getPlanDate());
			final Integer planTime1 = Convert.toInt(DateUtil.format(content.getPlanDate(), "yyyyMMdd"));
			final Integer planTime2 = Convert.toInt(DateUtil.format(new Date(), "yyyyMMdd"));
			if (planTime2 > planTime1) {
				final Integer days = Convert.toInt(DateUtil.betweenDay(content.getPlanDate(), new Date(), true));
				planDetailVo.setOverdueName("逾期" + days + "天");
			}
			resultList.add(planDetailVo);
		}
		return resultList;
	}

	/**
	 * 维修列表全部
	 * 新增查询排序条件
	 */
	@Override
	public IPage<MalFunctionPlanPageVO> elevatorPlanHistoryRepair(RepairPlanHistoryDTO queryDTO, IPage<MalFunctionPlanPageVO> page) {
		//测试数据
		IPage<MalFunctionPlanPageVO> pageList = baseMapper.elevatorPlanHistoryRepair(queryDTO, page);
		pageList.getRecords().forEach(e -> {
			if (Func.isNotBlank(e.getProblemItem())) {
				List<String> problemKeys = Func.toStrList(e.getProblemItem());
				List<String> problemNames = new ArrayList<>();
				for (String problemKey : problemKeys) {
					String problemName = DictCache.getValue("fault_problem", problemKey);
					problemNames.add(problemName);
				}
				e.setProblemItemNames(problemNames);
				if (ObjectUtil.isNotEmpty(e.getPlanContentUserVos())) {
					e.setPlanContentUserVos(this.filterNotWorkUser(e.getPlanContentUserVos(), e.getStatus(), e.getPlanId(), e.getTypeStatus()));
					e.setPlanContentUserVos(this.changeFirstUser(e.getPlanContentUserVos()));
				}
				if (!Func.isNull(e.getElevatorId())) {
					Integer isStop = elevatorService.selectElevatorDetail(e.getElevatorId()).getIsStop();
					e.setIsStop(isStop);
				}
			}
		});
		return pageList;
	}

	private List<PlanContentElevatorVo> getRescueHomeList(PlanContentSearchDTO planContentSearchDTO, Boolean isFinish) {
		List<Integer> status = new ArrayList<>(2);
		if (isFinish) {
			status.add(TaskStatusEnum.JY_RESCUE.getStatus());
			planContentSearchDTO.setStatusList(status);
		} else {
			status.add(TaskStatusEnum.JY_TO_START.getStatus());
			status.add(TaskStatusEnum.JY_PROCESSED.getStatus());
			status.add(TaskStatusEnum.JY_ARRIVE.getStatus());
			planContentSearchDTO.setStatusList(status);
		}
		List<PlanContentElevatorVo> list = baseMapper.getRescueHomeList(planContentSearchDTO);
		return list;
	}

	@Override
	public IPage<PlanDataPageVO> elevatorPlanHistoryBySkip(ByPlanHistorySkipDTO queryDTO, IPage<PlanDataPageVO> page) {
		IPage<PlanDataPageVO> planCheckPage = baseMapper.elevatorPlanHistoryBySkip(queryDTO, page);
		List<Long> planIds = planCheckPage.getRecords().stream().map(PlanDataPageVO::getPlanId).collect(Collectors.toList());
		List<MaintainPlanContentUser> planContentUserList = planContentUserService.list(Wrappers.<MaintainPlanContentUser>lambdaQuery().in(MaintainPlanContentUser::getPlanId, planIds));
		Map<Long, List<MaintainPlanContentUser>> planContentUserMap = planContentUserList.stream().collect(Collectors.groupingBy(MaintainPlanContentUser::getPlanId));
		for (PlanDataPageVO record : planCheckPage.getRecords()) {
			List<MaintainPlanContentUser> planContentUsers = planContentUserMap.get(record.getPlanId());
			// 封装状态描述
			record.setStatusDesc(TaskStatusEnum.getTaskName(record.getTypeStatus(), record.getStatus()));
			// 根据工单状态封装模板名称
			if (!record.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())) {
				// 封装关联人员签到状态，异常标签及过滤未工作人员
				planContentUsers = this.filterNotWorkUser(planContentUsers, record.getStatus(), record.getPlanId(), record.getTypeStatus());
			}
			// 封装关联人员组名称
			if (planContentUsers.size() > 0) {
				List<String> groupName = Func.toStrList(record.getUserDeptNames());
				record.setGroupNames(groupName);
			}
			// 当前用户放在第一位
			record.setPlanContentUserVos(this.changeFirstUser(planContentUsers));
			// 根据工单状态封装及时性 时效性标签描述
			if (record.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus()) || record.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())) {
				if (record.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())) {
					// 过长过短
					if (record.getWorkMinute() > 60) {
						record.setDuration(WorkTrackStatusEnum.TOO_LONG.getTypeName());
					} else if (record.getWorkMinute() < 25) {
						record.setDuration(WorkTrackStatusEnum.TOO_SHORT.getTypeName());
					}
				}

				if (ObjectUtil.isNotEmpty(record.getMaintainSignatureTime())) {
					// 逾期
					if (record.getAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus()) && ObjectUtil.isNotEmpty(record.getPlanOverdueDate())) {
						long maintainSignatureTime = DateUtil.parse(DateUtil.format(record.getMaintainSignatureTime(), "yyyy-MM-dd")).getTime();
						long overdueDate = record.getPlanOverdueDate().getTime();
						if (maintainSignatureTime > overdueDate) {
							long betweenDay = DateUtil.between(record.getPlanOverdueDate(), record.getMaintainSignatureTime(), DateUnit.DAY);
							record.setOverdueName("逾期" + betweenDay + "天");
						}
					}

					// 及时超时
					long betweenDay = DateUtil.between(record.getPlanDate(), record.getMaintainSignatureTime(), DateUnit.DAY);
					if (betweenDay > 0) {
						if (record.getPlanDate().compareTo(record.getMaintainSignatureTime()) < 0) {
							record.setTimeliness("超时" + betweenDay + "天");
						}
					} else if (betweenDay == 0) {
						record.setTimeliness(WorkTrackStatusEnum.IN_TIME.getTypeName());
					}
				}
			} else {
				// 逾期
				if (record.getAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus()) && ObjectUtil.isNotEmpty(record.getElevatorOverdueDate())) {
					long nowDate = DateUtil.parse(DateUtil.today()).getTime();
					long planDate = record.getPlanDate().getTime();
					long overdueDate = record.getElevatorOverdueDate().getTime();
					if (planDate <= nowDate && nowDate > overdueDate) {
						long betweenDay = DateUtil.between(record.getElevatorOverdueDate(), DateUtil.date(), DateUnit.DAY);
						record.setOverdueName("逾期" + betweenDay + "天");
					}
				}
				// 及时超时
				long betweenDay = DateUtil.between(record.getPlanDate(), new Date(), DateUnit.DAY);
				if (betweenDay > 0) {
					if (record.getPlanDate().compareTo(DateUtil.date()) < 0) {
						record.setTimeliness("超时" + betweenDay + "天");
					}
				}
			}
		}
		return planCheckPage;
	}

	@Override
	public IPage<MalFunctionPlanPageVO> elevatorPlanHistoryPjSkip(PjPlanHistorySkipDTO queryDTO, IPage<MalFunctionPlanPageVO> page) {
		IPage<MalFunctionPlanPageVO> pageList = baseMapper.elevatorPlanHistoryPjSkip(queryDTO, page);
		pageList.getRecords().forEach(e -> {
			if (ObjectUtil.isNotEmpty(e.getPlanContentUserVos())) {
				e.setPlanContentUserVos(this.filterNotWorkUser(e.getPlanContentUserVos(), e.getStatus(), e.getPlanId(), e.getTypeStatus()));
				e.setPlanContentUserVos(this.changeFirstUser(e.getPlanContentUserVos()));
			}
		});
		return pageList;
	}

	@Override
	public IPage<MyApproveVO> getMyApproveList(Long userId, Integer approveStatus, IPage<MyApproveVO> page) {
		IPage<MyApproveVO> myApproveVOList = baseMapper.getMyApproveList(userId, approveStatus, page);
		// 数据处理
		List<MyApproveVO> records = myApproveVOList.getRecords();
		for (MyApproveVO vo : records) {
			//插入当前用户名
			String realName = userService.getOne(new LambdaQueryWrapper<User>().eq(BaseEntity::getId, userId)).getRealName();
			vo.setApproveUser(realName);
			//时间精确到分钟
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
			String sdfTime = sdf.format(vo.getCreateTime());
			vo.setSdfTime(sdfTime);
			//维修进度格式化，暂时if else
			Integer status = vo.getStatus();
			String statusName = null;
			switch (status) {
				case 1:
					statusName = "待处理";
					break;
				case 2:
					statusName = "待开始";
					break;
				case 3:
					statusName = "维修中";
					break;
				case 4:
					statusName = "已完成";
					break;
				case 5:
					statusName = "已撤回";
					break;
				case 6:
					statusName = "已驳回";
					break;
				case 7:
					statusName = "已关闭";
					break;
				default:
					// 如果status不是上述中的任意一个，可以选择默认情况下将statusName设置为空字符串或者设置为null
					statusName = "未知状态";
					break;
			}
			vo.setStatusName(statusName);

			// 字典值拼接
			String problemItem = vo.getProblemItem();
			if (!Func.isNull(problemItem)) {
				String[] split = problemItem.split(",");
				String[] problemNames = new String[split.length];
				for (int i = 0; i < split.length; i++) {
					String s = baseMapper.dictValue(split[i]);
					problemNames[i] = s;
				}
				vo.setProblemNames(problemNames);
			}


		}
		myApproveVOList.setRecords(records);
		return myApproveVOList;
	}

	@Override
	public Map<String, Object> getPlanAllowSign(Long planId) {
		Map<String, Object> resultMap = new HashMap<>(2);
		resultMap.put("allow", Boolean.TRUE);
		MaintainPlanContent planContent = super.getById(planId);
		final Long elevatorId = planContent.getElevatorId();
		log.info("获取的电梯id================" + planContent.getElevatorId());
		List<Long> userPlanIds = this.listUserPlan(planContent.getTypeStatus(), planId, AuthUtil.getUserId());
		if (ObjectUtil.isNotEmpty(userPlanIds) && userPlanIds.size() >= 1) {
			int count = signService.count(Wrappers.<MaintainSign>lambdaQuery()
				.in(MaintainSign::getPlanId, userPlanIds)
				.eq(MaintainSign::getUserId, AuthUtil.getUserId())
				.isNull(MaintainSign::getSignOutTime));
			if (count > 0) {
				resultMap.put("allow", Boolean.FALSE);
				resultMap.put("msg", "有未签退的" + MaintainPlanContentEnum.getName(planContent.getTypeStatus()) + "任务，请先签退，再开始新的任务");
			}
		}
		// 2023-11-24 新增未签退具体信息
		PlanSignCheckVO result = signService.planSignOutCheck(planId);
		resultMap.put("detail", result);
		return resultMap;
	}

	@Override
	public Boolean planDetailUpdate(MaintainPlanContent planContent) {

		long deliverTime = planContent.getFinishDate().getTime() - 5 * 60000;
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("planId", planContent.getId());
		jsonObject.put("finishDate", planContent.getFinishDate());
		normalSend.sendPlanFinishDate(deliverTime, jsonObject.toJSONString());

		return this.updateById(planContent);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void updateElevatorStrategy(List<Long> elevatorIds) {
		this.updateElevatorStrategy(elevatorIds, false);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void updateElevatorStrategy(List<Long> elevatorIds, boolean isUpdateOverdueDate) {
		if (Func.isEmpty(elevatorIds)) {
			return;
		}

		List<ElevatorPlanStrategy> planStrategyList = new ArrayList<>();
		for (Long elevatorId : elevatorIds) {
			ElevatorPlanStrategy strategy = elevatorPlanStrategyService.getByElevatorId(elevatorId);
			List<MaintainPlanContentExtVO> planContentList = maintainPlanContentExtService.maintainPlanList(elevatorId);
			if (Func.isEmpty(planContentList)) {
				if (Func.isNotEmpty(strategy)) {
					strategy.setNextPlanId(null);
					strategy.setNextPlanDate(null);
					strategy.setOverdueDate(null);
					strategy.setOtherOverdue(null);
					strategy.setLastDate(null);
					elevatorPlanStrategyService.updateById(strategy);
				}
				continue;
			}

			// 已完成的工单
			List<MaintainPlanContentExtVO> finishPlanList = planContentList.stream()
				.filter(t -> t.getPlanStatus() == TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus() || t.getPlanStatus() == TaskStatusEnum.BY_SIGN.getStatus())
				.sorted(Comparator.comparing(MaintainPlanContentExtVO::getMaintainSignatureTime).reversed()).collect(Collectors.toList());

			// 未完成的工单
			List<Integer> notStartStatus = Arrays.asList(TaskStatusEnum.BY_DISABLE.getStatus(), TaskStatusEnum.BY_PROCESSED.getStatus(), TaskStatusEnum.BY_FINISH.getStatus());
			List<MaintainPlanContentExtVO> notStartPlanList = planContentList.stream()
				.filter(t -> notStartStatus.contains(t.getPlanStatus()))
				.sorted(Comparator.comparing(MaintainPlanContentExtVO::getPlanDate)).collect(Collectors.toList());

			if (Func.isEmpty(strategy)) {
				strategy = new ElevatorPlanStrategy();
			}
			strategy.setOtherOverdue(this.otherOverdueHandle(notStartPlanList));
			// 最末次保养计划日期
			Date lastDate = planContentList.stream().map(t -> t.getPlanDate()).max(Comparator.comparing(Date::getTime)).get();
			strategy.setLastDate(lastDate);

			/**
			 * 下次保养计划-逾期风险判断规则：
			 * 下次保养计划的日期，如果与上次维保签字日期间隔超15天以上（在当前逾期临界日期之后），则视为存在逾期风险。
			 */
			// 首保未开始
			if (Func.isEmpty(finishPlanList)) {
				MaintainPlanContentExtVO nextPlan = notStartPlanList.get(0);
				strategy.setElevatorId(nextPlan.getElevatorId());
				strategy.setNextPlanId(nextPlan.getPlanId());
				strategy.setNextPlanDate(nextPlan.getPlanDate());
				strategy.setIsFirst(0);
				strategy.setOverdueDate(DateUtil.offsetDay(nextPlan.getPlanDate(), 15));
				strategy.setTenantId(nextPlan.getTenantId());
				planStrategyList.add(strategy);
				continue;
			}

			// 工单已全部做完
			if (Func.isEmpty(notStartPlanList)) {
				MaintainPlanContentExtVO previousPlan = finishPlanList.get(0);
				strategy.setElevatorId(previousPlan.getElevatorId());
				strategy.setPreviousPlanId(previousPlan.getPlanId());
				String signatureTime = DateUtil.format(previousPlan.getMaintainSignatureTime(), "yyyy-MM-dd");
				strategy.setPreviousPlanDate(DateUtil.parseDate(signatureTime));
				strategy.setNextPlanId(null);
				strategy.setNextPlanDate(null);
				strategy.setIsFirst(1);
				if (isUpdateOverdueDate) {
					strategy.setOverdueDate(DateUtil.offsetDay(DateUtil.parseDate(signatureTime), 15));
				}
				strategy.setTenantId(previousPlan.getTenantId());
				planStrategyList.add(strategy);
				continue;
			}

			// 上次保养计划
			MaintainPlanContentExtVO plan1 = finishPlanList.get(0);
			Date signatureTime = DateUtil.parseDate(DateUtil.format(plan1.getMaintainSignatureTime(), "yyyy-MM-dd"));
			// 未来保养计划排期
			List<MaintainPlanContentExtVO> featurePlanList = notStartPlanList.stream().filter(t -> DateUtil.compare(t.getPlanDate(), signatureTime) >= 0)
				.sorted(Comparator.comparing(MaintainPlanContentExtVO::getPlanDate)).collect(Collectors.toList());
			strategy.setElevatorId(elevatorId);
			strategy.setPreviousPlanId(plan1.getPlanId());
			strategy.setPreviousPlanDate(signatureTime);
			if (Func.isEmpty(featurePlanList)) {
				strategy.setNextPlanId(null);
				strategy.setNextPlanDate(null);
			} else {
				MaintainPlanContentExtVO plan2 = featurePlanList.get(0);
				strategy.setNextPlanId(plan2.getPlanId());
				strategy.setNextPlanDate(plan2.getPlanDate());
			}
			strategy.setIsFirst(1);
			if (isUpdateOverdueDate) {
				strategy.setOverdueDate(DateUtil.offsetDay(signatureTime, 15));
			}
			strategy.setTenantId(plan1.getTenantId());
			planStrategyList.add(strategy);
		}

		elevatorPlanStrategyService.saveOrUpdateBatch(planStrategyList);
	}

	/**
	 * 其他剩余计划-逾期风险判断规则：
	 * 除下一次保养计划外，若当前时间往后的剩余排期计划中，存在与前一个排期计划间隔超15天的情况，则视为存在逾期风险。
	 *
	 * @param notStartPlanList
	 * @return
	 */
	private Integer otherOverdueHandle(List<MaintainPlanContentExtVO> notStartPlanList) {
		if (notStartPlanList.size() <= 1) {
			return null;
		}

		// 未来保养计划排期
		Date today = DateUtil.parseDate(DateUtil.format(DateUtil.date(), "yyyy-MM-dd"));
		List<MaintainPlanContentExtVO> featurePlanList = notStartPlanList.stream().filter(t -> DateUtil.compare(t.getPlanDate(), today) >= 0)
			.sorted(Comparator.comparing(MaintainPlanContentExtVO::getPlanDate)).collect(Collectors.toList());
		if (Func.isEmpty(featurePlanList)) {
			return null;
		}

		MaintainPlanContentExtVO nextPlan = featurePlanList.get(0);
		// 在保状态
		List<Integer> maintainStatusList = Arrays.asList(ElevatorMaintainStatusEnums.CONTRACT_IN_TIME.getId(), ElevatorMaintainStatusEnums.CONTRACT_OUT_TIME.getId(), ElevatorMaintainStatusEnums.DIS_ENABLE.getId(), ElevatorMaintainStatusEnums.OUT_TIME_STOP.getId(), ElevatorMaintainStatusEnums.OUT_TIME_END.getId(), ElevatorMaintainStatusEnums.OUT_TIME_END_HAS_NEXT.getId());
		// 只处理电梯在保且为年审梯的工单
		boolean checkTag = !maintainStatusList.contains(nextPlan.getMaintainStatus()) || !Func.equalsSafe(nextPlan.getElevatorUseType(), 0);
		if (checkTag) {
			return null;
		}

		Integer otherOverdue = 0;
		Date firstDate = nextPlan.getPlanDate();
		for (int i = 1; i < featurePlanList.size(); i++) {
			MaintainPlanContentExtVO notStartPlan = featurePlanList.get(i);
			if (DateUtil.betweenDay(firstDate, notStartPlan.getPlanDate(), true) > 15) {
				otherOverdue = 1;
				break;
			} else {
				firstDate = notStartPlan.getPlanDate();
			}
		}
		return otherOverdue;
	}

	@Override
	public Boolean botSendMsg(Long planId, Integer isStop) {
		MaintainPlanContent planContent = super.getById(planId);
		if (ObjectUtil.isNotEmpty(planContent.getElevatorId())) {
			ElevatorSimpleInfoVO elevator = this.getElevatorSimpleInfo(planId);
			List<MaintainPlanContentUser> users = planContentUserService.listUserByPlan(planId);
			String userNames = "";
			if (ObjectUtil.isNotEmpty(users)) {
				userNames = users.stream().map(MaintainPlanContentUser::getUserName).collect(Collectors.joining("/"));
			}
			List<SimpleUserVO> userVOS = userService.selectElevatorSubUser(planContent.getElevatorId());
			if (ObjectUtil.isNotEmpty(userVOS)) {
				String finalUserNames = userNames;
				String params = planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_BY.getId())
					? "pages/elevatorTask/workOrders/detail?planId=" + planId + "&elevatorId=" + planContent.getElevatorId() : "packPage/repDetail/repDetail?planId=" + planId + "&elevatorId=" + planContent.getElevatorId();
				userVOS.forEach(e -> {
					if (ObjectUtil.isNotEmpty(e.getOpenid())) {
						HashMap<String, Object> map = new HashMap<>(3);
						HashMap<String, String> templateMap = new HashMap<>(5);
						templateMap.put("first", String.format("您所关注的电梯【%s】", isStop.equals(ElevatorStatusEnum.NORMAL.getStatus()) ? "已恢复正常使用" : "已停梯"));
						templateMap.put("keyword1", elevator.getBuildingName());
						templateMap.put("keyword2", elevator.getElevatorAddress());
						templateMap.put("keyword3", planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_BY.getId()) ? "电梯保养" : "电梯维修");
						templateMap.put("keyword4", DateUtil.format(planContent.getFinishDate(), "yyyy年MM月dd日 HH:mm") + "结束");
						templateMap.put("keyword5", finalUserNames);
						templateMap.put("remark", "点击查看该电梯维保详情");
						templateMap.put("params", params);
						map.put("sendType", sendType);
						map.put("openid", e.getOpenid());
						map.put("params", templateMap);
						map.put("templateId", TemplateMsgConstant.T_ELEVATOR_STOP_BOT);
						asyncHttpUtil.createPost(estateApiUrl + official_accounts_push_url, JSONObject.toJSONString(map));
					}
				});
			}
		}
		return Boolean.TRUE;
	}

	@Override
	public Map<String, Map<String, Object>> maintainPlanCalendarData(MaintainPlanCalendarDataDTO calendarDataDTO) {
		List<MaintainPlanContent> list = baseMapper.maintainPlanCalendarList(calendarDataDTO);
		Map<String, Map<String, Object>> map = list.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(), "yyyyMd"), Collectors.collectingAndThen(Collectors.toList(), t -> {
				List<MaintainPlanContent> groupList = t;
				Map<String, Object> contentMap = new HashMap<>(2);
				contentMap.put("elevatorCount", groupList.stream().map(MaintainPlanContent::getElevatorId).distinct().count());
				contentMap.put("list", groupList);
				// 状态标识
				boolean statusFlag = groupList.stream().anyMatch(a -> Arrays.asList(1, 2, 3).contains(a.getStatus()));
				contentMap.put("statusFlag", statusFlag);
				return contentMap;
			})
		));
		return map;
	}

	@Override
	public String getDatePlanInfoListDownExcel(MaintainPlanCalendarDataDownDTO calendarDataDTO) throws IOException {
		this.excelDownConditionsHandle(calendarDataDTO);
		List<PlanInfoDownExcelVO> list = baseMapper.getDatePlanInfoListDownExcel(calendarDataDTO);
		final List<String> buildingNames = list.stream().map(PlanInfoDownExcelVO::getBuildingName).distinct().collect(Collectors.toList());
		Integer buildingSize = Convert.toInt(buildingNames.size(), 0);
		StringBuilder fileName = new StringBuilder("(").append(calendarDataDTO.getStartDate()).append("～").append(calendarDataDTO.getEndDate()).append(")");
		String fileDateName = fileName.toString().replace("-", "") + "_" + DateUtil.format(new Date(), "yyyyMMddHHmmss");
		if (buildingSize > 0) {
			String buildingName = buildingSize == 1 ? buildingNames.get(0) : "多个项目";
			fileDateName = buildingName + "保养计划安排" + fileDateName;
		}

		List<List<String>> rows = new ArrayList<>();
		List<String> title = CollUtil.newArrayList("保养日期", "星期", "维保单位名称", "项目名称", "梯号", "单位内编号", "设备注册代码", "使用登记证编号", "维保员");
		ExcelWriter excelWriter = null;
		rows.add(title);
		for (PlanInfoDownExcelVO planInfoDownExcelVo : list) {
			List<String> row = new ArrayList<>();
			row.add(planInfoDownExcelVo.getPlanDate());
			row.add(DateUtil.dayOfWeekEnum(planInfoDownExcelVo.getWorkDate()).toChinese().replace("星期", ""));
			row.add(planInfoDownExcelVo.getTenantName());
			row.add(planInfoDownExcelVo.getBuildingName());
			row.add(planInfoDownExcelVo.getElevatorAddress());
			row.add(Func.toStr(planInfoDownExcelVo.getRegisterNumber(), "--"));
			row.add(Func.toStr(planInfoDownExcelVo.getPrivateNum(), "--"));
			row.add(Func.toStr(planInfoDownExcelVo.getEquipmentRegisterNumber(), "--"));
			row.add(planInfoDownExcelVo.getMaintainUser());
			rows.add(row);
		}
		excelWriter = ExcelUtil.getBigWriter(rows.size());
		excelWriter.setColumnWidth(0, 30);
		excelWriter.setColumnWidth(1, 15);
		excelWriter.setColumnWidth(2, 30);
		excelWriter.setColumnWidth(3, 30);
		excelWriter.setColumnWidth(4, 30);
		excelWriter.setColumnWidth(5, 30);
		excelWriter.setColumnWidth(6, 30);
		excelWriter.setColumnWidth(7, 30);
		excelWriter.setColumnWidth(8, 100);
		excelWriter.merge(8, "保养计划安排", true);
		if (calendarDataDTO.getType() == 6) {
			excelWriter.merge(8, "您好，为保证电梯设备正常运行，维保单位 " + fileName.toString().replace("-", "/") + " 对以下电梯的例行保养计划具体安排时间如下:", true);
		} else {
			excelWriter.merge(8, "您好，为保证电梯设备正常运行，维保单位 " + calendarDataDTO.getSimpleDateName() + " " + fileName.toString().replace("-", "/") + " 对以下电梯的例行保养计划具体安排时间如下:", true);
		}
		excelWriter.write(rows, true);

		// 设置“维保员”列的数据为左对齐
		for (int i = 3; i <= list.size() + 2; i++) {
			Cell cell = excelWriter.getCell(8, i, true);
			CellStyle cellStyle = cell.getCellStyle();
			//必须新创建单元格样式，直接修改原单元格样式可能影响到其它单元格，因为样式可以复用的
			CellStyle cellStyleDest = excelWriter.createCellStyle(8, i);
			//原单元格样式不为空，先拷贝原单元格样式至新创建的单元格样式
			if (cellStyle != null) {
				cellStyleDest.cloneStyleFrom(cellStyle);
			}
			cellStyleDest.setAlignment(HorizontalAlignment.LEFT);
			cell.setCellStyle(cellStyleDest);
		}

		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		excelWriter.flush(bos, true);
		InputStream is = new ByteArrayInputStream(bos.toByteArray());
		String downLink = ossBuilder.template().putFile(BladeOssRuleExt.DIV_FILE_NAME + fileDateName + ".xlsx", is).getLink();
		excelWriter.close();
		is.close();

		return downLink;
	}

	@Override
	public int getDatePlanInfoListDownStatistics(MaintainPlanCalendarDataDownDTO calendarDataDTO) {
		this.excelDownConditionsHandle(calendarDataDTO);
		List<PlanInfoDownExcelVO> list = baseMapper.getDatePlanInfoListDownExcel(calendarDataDTO);
		return list.size();
	}

	/**
	 * excel导出条件类型处理
	 *
	 * @param calendarDataDTO
	 * @return
	 */
	private MaintainPlanCalendarDataDownDTO excelDownConditionsHandle(MaintainPlanCalendarDataDownDTO calendarDataDTO) {
		if (calendarDataDTO.getType() == 6 && (Func.isBlank(calendarDataDTO.getStartDate()) || Func.isBlank(calendarDataDTO.getEndDate()))) {
			throw new ServiceException("保养计划日期区间不能为空");
		} else {
			Date curDay = DateUtil.date();
			Date startDate = null;
			Date endDate = null;
			String simpleDateName = null;
			switch (calendarDataDTO.getType()) {
				case 0: {
					// 今天
					startDate = curDay;
					endDate = curDay;
					simpleDateName = "今天";
					break;
				}
				case 1: {
					// 本周
					startDate = DateUtil.beginOfWeek(curDay);
					endDate = DateUtil.endOfWeek(curDay);
					simpleDateName = "本周";
					break;
				}
				case 2: {
					// 本月
					startDate = DateUtil.beginOfMonth(curDay);
					endDate = DateUtil.endOfMonth(curDay);
					simpleDateName = String.format("%s月", DateUtil.month(curDay) + 1);
					break;
				}
				case 3: {
					// 后1个月
					Date tempStartDate = DateUtil.offsetMonth(curDay, 1);
					startDate = DateUtil.beginOfMonth(tempStartDate);
					endDate = DateUtil.endOfMonth(tempStartDate);
					simpleDateName = String.format("%s月", DateUtil.month(tempStartDate) + 1);
					break;
				}
				case 4: {
					// 后2个月
					Date tempStartDate = DateUtil.offsetMonth(curDay, 1);
					Date tempEndDate = DateUtil.offsetMonth(curDay, 2);
					startDate = DateUtil.beginOfMonth(tempStartDate);
					endDate = DateUtil.endOfMonth(tempEndDate);
					simpleDateName = String.format("%s月、%s月", DateUtil.month(tempStartDate) + 1, DateUtil.month(tempEndDate) + 1);
					break;
				}
				case 5: {
					// 后3个月
					Date tempStartDate = DateUtil.offsetMonth(curDay, 1);
					Date tempEndDate = DateUtil.offsetMonth(curDay, 3);
					startDate = DateUtil.beginOfMonth(tempStartDate);
					endDate = DateUtil.endOfMonth(tempEndDate);
					simpleDateName = String.format("%s月、%s月、%s月", DateUtil.month(tempStartDate) + 1, DateUtil.month(tempEndDate), DateUtil.month(tempEndDate) + 1);
					break;
				}
				default: {
					startDate = DateUtil.parseDate(calendarDataDTO.getStartDate());
					endDate = DateUtil.parseDate(calendarDataDTO.getEndDate());
				}
			}
			calendarDataDTO.setStartDate(DateUtil.formatDate(startDate));
			calendarDataDTO.setEndDate(DateUtil.formatDate(endDate));
			calendarDataDTO.setSimpleDateName(simpleDateName);
		}

		return calendarDataDTO;
	}

	@Override
	public PlanCalendarListStatisticsVO getPlanCalendarListStatistics(MaintainPlanCalendarDataDTO calendarDataDTO) {
		PlanCalendarListStatisticsVO statistics = new PlanCalendarListStatisticsVO();
		List<MaintainPlanContent> list = baseMapper.maintainPlanCalendarList(calendarDataDTO);
		statistics.setElevatorCount(list.stream().map(t -> t.getElevatorId()).distinct().count());
		statistics.setPlanTaskCount(list.size());
		statistics.setMaintainSignatureCount(list.stream().filter(t -> t.getStatus() == TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus() || t.getStatus() == TaskStatusEnum.BY_SIGN.getStatus()).count());
		statistics.setCustomerSignatureCount(list.stream().filter(t -> t.getStatus() == TaskStatusEnum.BY_SIGN.getStatus()).count());
		return statistics;
	}

	@Override
	public List<PlanSimpleInfoDTO> listPlanSimpleByElevatorIds(PlanCheckStatisticsQueryDTO queryDTO, List<Long> elevatorIds, int typeStatus) {
		return baseMapper.listPlanSimpleByElevatorIds(queryDTO, elevatorIds, typeStatus);
	}

	@Override
	public List<WxBuildingSimpleVO> selectWxRepetitionBuildingSimpleByIds(List<Long> buildingIds, IPage<WxBuildingSimpleVO> page) {
		return baseMapper.selectWxRepetitionBuildingSimpleByIds(buildingIds, page);
	}

	@Override
	public List<WxElevatorSimpleVO> getElevatorSimpleAndWxPlan(List<Long> elevatorIds, PlanCheckStatisticsQueryDTO queryDTO) {
		return baseMapper.getElevatorSimpleAndWxPlan(elevatorIds, queryDTO);
	}

	@Override
	public Map<String, Object> selectElevatorFilesAllPlan(Long elevatorId, String startDate, String endDate) {
		Map<String, Object> resultMap = new HashMap<>();
		List<Map<String, Object>> result = new ArrayList<>();
		List<ElevatorFilesPlanListVO> allList = new ArrayList<>();
		List<ElevatorFilesPlanListVO> byList = baseMapper.selectElevatorFilesAllPlanBy(elevatorId, startDate, endDate);
		if (Func.isNotEmpty(byList)) {
			byList.forEach(e -> {
				e.setSortDate(e.getMaintainSignatureTime());
				e.setStatusName(TaskStatusEnum.getTaskName(e.getTypeStatus(), e.getStatus()));
				if (Func.isNotEmpty(e.getTemplateName())) {
					e.setTemplateNames(Func.toStrList(e.getTemplateName()));
				}
				// 逾期
				if (e.getAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus()) && ObjectUtil.isNotEmpty(e.getPlanOverdueDate())) {
					long maintainSignatureTime = DateUtil.parse(DateUtil.format(e.getMaintainSignatureTime(), "yyyy-MM-dd")).getTime();
					long overdueDate = e.getPlanOverdueDate().getTime();
					if (maintainSignatureTime > overdueDate) {
						long betweenDay = DateUtil.between(e.getPlanOverdueDate(), e.getMaintainSignatureTime(), DateUnit.DAY);
						e.setOverdueDayName("逾期" + betweenDay + "天");
					}
				}
				if (Func.isNotEmpty(e.getDeferType()) && (e.getDeferType().equals(1) || e.getDeferType().equals(5))) {
					e.setDeferTypeName("延期保养");
				}
				if (e.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())) {
					// 过长过短
					if (Convert.toInt(e.getWorkMinute(), 0) > 60) {
						e.setDuration(WorkTrackStatusEnum.TOO_LONG.getTypeName());
					} else if (e.getWorkMinute() < 25) {
						e.setDuration(WorkTrackStatusEnum.TOO_SHORT.getTypeName());
					}
				}
				// 及时超时
				long betweenDay = DateUtil.between(e.getPlanDate(), e.getMaintainSignatureTime(), DateUnit.DAY);
				if (betweenDay > 0) {
					if (e.getPlanDate().compareTo(e.getMaintainSignatureTime()) < 0) {
						e.setTimeliness("超时" + betweenDay + "天");
					}
				} else if (betweenDay == 0) {
					e.setTimeliness(WorkTrackStatusEnum.IN_TIME.getTypeName());
				}
			});
			allList.addAll(byList);
		}
		List<ElevatorFilesPlanListVO> wxList = baseMapper.selectElevatorFilesAllPlanWx(elevatorId, startDate, endDate);
		if (Func.isNotEmpty(wxList)) {
			wxList.forEach(e -> {
				e.setSortDate(e.getPlanEndTime());
				e.setStatusName(TaskStatusEnum.getTaskName(e.getTypeStatus(), e.getStatus()));
				// 封装故障现象信息
				if (StringUtil.isNotBlank(e.getProblemItem())) {
					List<String> problemKeys = Func.toStrList(e.getProblemItem());
					List<String> problemNames = new ArrayList<>();
					for (String problemKey : problemKeys) {
						String problemName = DictCache.getValue("fault_problem", problemKey);
						problemNames.add(problemName);
					}
					e.setProblemItemNames(problemNames);
				}
			});
			allList.addAll(wxList);
		}
		List<ElevatorFilesPlanListVO> pjList = baseMapper.selectElevatorFilesAllPlanPj(elevatorId, startDate, endDate);
		if (Func.isNotEmpty(pjList)) {
			pjList.forEach(e -> {
				if (StringUtil.isNotBlank(e.getPartsName())) {
					String[] partsName = Func.toStrArray("&amp;", e.getPartsName());
					e.setPartsName(partsName[partsName.length - 1]);
				}
				e.setSortDate(e.getPlanEndTime());
				e.setStatusName(TaskStatusEnum.getTaskName(e.getTypeStatus(), e.getStatus()));
			});
			allList.addAll(pjList);
		}
		List<ElevatorFilesPlanListVO> jyList = baseMapper.selectElevatorFilesAllPlanJy(elevatorId, startDate, endDate);
		if (Func.isNotEmpty(jyList)) {
			jyList.forEach(e -> {
				e.setSortDate(e.getPlanEndTime());
				e.setStatusName(TaskStatusEnum.getTaskName(e.getTypeStatus(), e.getStatus()));
				e.setTrapTypeName(e.getTrapType() == 0 ? "困人" : "伤人");
			});
			allList.addAll(jyList);
		}

		//2023-12-15 新增质检和事务
		List<ElevatorFilesPlanListVO> affairList = baseMapper.selectElevatorFilesAllPlanSw(elevatorId, startDate, endDate);
		List<ElevatorFilesPlanListVO> checkList = baseMapper.selectElevatorFilesAllPlanZj(elevatorId, startDate, endDate);
		affairList.addAll(checkList);
		if (Func.isNotEmpty(affairList)) {
			affairList.forEach(e -> {
				e.setSortDate(e.getPlanEndTime());
				e.setStatusName(TaskStatusEnum.getTaskName(e.getTypeStatus(), e.getStatus()));
			});
			allList.addAll(affairList);
		}

		// 整改工单
		List<ElevatorFilesPlanListVO> zgList = baseMapper.selectElevatorFilesAllPlanZg(elevatorId, startDate, endDate);
		if (Func.isNotEmpty(zgList)) {
			zgList.forEach(e -> {
				e.setSortDate(e.getPlanEndTime());
				e.setStatusName(TaskStatusEnum.getTaskName(e.getTypeStatus(), e.getStatus()));
			});
			allList.addAll(zgList);
		}
		if (Func.isNotEmpty(allList)) {
			Map<String, List<ElevatorFilesPlanListVO>> yearGroup = allList.stream().collect(Collectors.groupingBy(e -> DateUtil.format(e.getSortDate(), "yyyy")));
			List<String> yearList = new ArrayList<>(yearGroup.keySet());
			Collections.sort(yearList);
			Collections.reverse(yearList);
			yearList.forEach(e -> {
				List<ElevatorFilesPlanListVO> yearPlanList = yearGroup.get(e);
				Map<String, List<ElevatorFilesPlanListVO>> dayGroup = yearPlanList.stream().collect(Collectors.groupingBy(j -> DateUtil.format(j.getSortDate(), "yyyy-MM-dd")));
				List<String> dayList = new ArrayList<>(dayGroup.keySet());
				Collections.sort(dayList);
				Collections.reverse(dayList);
				List<Map<String, Object>> dayGroupResult = new ArrayList<>();
				dayList.forEach(j -> {
					Map<String, Object> dayMap = new HashMap<>();
					dayMap.put("label", j);
					List<ElevatorFilesPlanListVO> dayItem = dayGroup.get(j);
					dayItem.sort(Comparator.comparing(ElevatorFilesPlanListVO::getSortDate).reversed());
					dayMap.put("value", dayItem);
					dayGroupResult.add(dayMap);
				});
				Map<String, Object> yearMap = new HashMap<>();
				yearMap.put("label", e);
				yearMap.put("value", dayGroupResult);
				result.add(yearMap);
			});
		}

		int planTotal = baseMapper.selectElevatorPlanTotal(elevatorId);
		resultMap.put("label", "已完成任务(" + planTotal + ")");
		resultMap.put("value", result);
		return resultMap;
	}

	@Override
	public Map<String, Object> selectElevatorFilesAllPlanWorkItem(Long elevatorId, Long partsId, String startDate, String endDate, Long floorStandIds) {
		Map<String, Object> resultMap = new HashMap<>();
		List<Map<String, Object>> result = new ArrayList<>();
		List<ElevatorPartWorkVo> allList = new ArrayList<>();
		List<ElevatorPartWorkVo> byList = baseMapper.getWorkListBy(elevatorId, partsId, startDate, endDate);
		if (Func.isNotEmpty(byList)) {
			List<Long> ids = byList.stream().map(ElevatorPartWorkVo::getId).collect(Collectors.toList());
			List<MaintainCheckRecord> workImageList = baseMapper.getWorkImageList(ids);
			Map<Long, List<MaintainCheckRecord>> listMap = workImageList.stream().collect(Collectors.groupingBy(MaintainCheckRecord::getCheckHistoryId));
			for (ElevatorPartWorkVo elevatorPartWorkVo : byList) {
				List<String> imgUrl = new ArrayList<>();
				List<MaintainCheckRecord> maintainCheckRecords = listMap.get(elevatorPartWorkVo.getId());
				elevatorPartWorkVo.setRecords(maintainCheckRecords);
				if (maintainCheckRecords != null && maintainCheckRecords.size() > 0) {
					List<JSONObject> jsonObjects = maintainCheckRecords.stream().map(MaintainCheckRecord::getRecordDataValue).collect(Collectors.toList());
					elevatorPartWorkVo.setRecordDataValues(jsonObjects);
					imgUrl.addAll(WatermarkImgUtils.findImgVideoUrl(jsonObjects.toString()));
				}
				imgUrl.addAll(WatermarkImgUtils.findImgVideoUrl(elevatorPartWorkVo.getRecordData().toJSONString()));
				elevatorPartWorkVo.setImgUrl(imgUrl);
			}
			allList.addAll(byList);
		}

		List<ElevatorPartWorkVo> wxList = baseMapper.getWorkListWx(elevatorId, partsId, floorStandIds, startDate, endDate);
		if (Func.isNotEmpty(wxList)) {
			wxList.forEach(e -> {
				// 封装故障现象信息
				List<String> problemNames = new ArrayList<>();
				if (StringUtil.isNotBlank(e.getProblemItem())) {
					List<String> problemKeys = Func.toStrList(e.getProblemItem());
					for (String problemKey : problemKeys) {
						String problemName = DictCache.getValue("fault_problem", problemKey);
						problemNames.add(problemName);
					}
				}
				if (StringUtil.isNotBlank(e.getProblemOtherDesc())) {
					problemNames.add(e.getProblemOtherDesc());
				}
				e.setProblemItemNames(problemNames);
			});
			allList.addAll(wxList);
		}
		List<ElevatorPartWorkVo> pjList = baseMapper.getWorkListPj(elevatorId, partsId, floorStandIds, startDate, endDate);
		if (Func.isNotEmpty(pjList)) {
			allList.addAll(pjList);
		}
		if (Func.isNotEmpty(allList)) {
			Map<String, List<ElevatorPartWorkVo>> yearGroup = allList.stream().collect(Collectors.groupingBy(e -> DateUtil.format(e.getCreateTime(), "yyyy")));
			List<String> yearList = new ArrayList<>(yearGroup.keySet());
			Collections.sort(yearList);
			Collections.reverse(yearList);
			yearList.forEach(e -> {
				List<ElevatorPartWorkVo> yearPlanList = yearGroup.get(e);
				Map<String, List<ElevatorPartWorkVo>> dayGroup = yearPlanList.stream().collect(Collectors.groupingBy(j -> DateUtil.format(j.getCreateTime(), "yyyy-MM-dd")));
				List<String> dayList = new ArrayList<>(dayGroup.keySet());
				Collections.sort(dayList);
				Collections.reverse(dayList);
				List<Map<String, Object>> dayGroupResult = new ArrayList<>();
				dayList.forEach(j -> {
					Map<String, Object> dayMap = new HashMap<>();
					dayMap.put("label", j);
					List<ElevatorPartWorkVo> dayItem = dayGroup.get(j);
					dayItem.sort(Comparator.comparing(ElevatorPartWorkVo::getCreateTime).reversed());
					dayMap.put("value", dayItem);
					dayGroupResult.add(dayMap);
				});
				Map<String, Object> yearMap = new HashMap<>();
				yearMap.put("label", e);
				yearMap.put("value", dayGroupResult);
				result.add(yearMap);
			});

		}
		int byCount = baseMapper.getWorkListByCount(elevatorId, partsId);
		int wxCount = baseMapper.getWorkListWxCount(elevatorId, partsId, floorStandIds);
		int pjCount = baseMapper.getWorkListPjCount(elevatorId, partsId, floorStandIds);
		resultMap.put("label", "维保工作(" + (byCount + wxCount + pjCount) + ")");
		resultMap.put("value", result);
		return resultMap;
	}

	@Override
	public Map<String, Object> selectElevatorFilesByPlanWorkItem(Long elevatorId, Long partsId, String startDate, String endDate) {
		Map<String, Object> resultMap = new HashMap<>();
		List<Map<String, Object>> result = new ArrayList<>();
		List<ElevatorPartWorkVo> allList = new ArrayList<>();
		int byCount = baseMapper.getWorkListByCount(elevatorId, partsId);
		List<ElevatorPartWorkVo> byList = baseMapper.getWorkListBy(elevatorId, partsId, startDate, endDate);
		if (Func.isNotEmpty(byList)) {
			List<Long> ids = byList.stream().map(ElevatorPartWorkVo::getId).collect(Collectors.toList());
			List<MaintainCheckRecord> workImageList = baseMapper.getWorkImageList(ids);
			Map<Long, List<MaintainCheckRecord>> listMap = workImageList.stream().collect(Collectors.groupingBy(MaintainCheckRecord::getCheckHistoryId));
			for (ElevatorPartWorkVo elevatorPartWorkVo : byList) {
				List<String> imgUrl = new ArrayList<>();
				List<MaintainCheckRecord> maintainCheckRecords = listMap.get(elevatorPartWorkVo.getId());
				elevatorPartWorkVo.setRecords(maintainCheckRecords);
				if (maintainCheckRecords != null && maintainCheckRecords.size() > 0) {
					List<JSONObject> jsonObjects = maintainCheckRecords.stream().map(MaintainCheckRecord::getRecordDataValue).collect(Collectors.toList());
					elevatorPartWorkVo.setRecordDataValues(jsonObjects);
					imgUrl.addAll(WatermarkImgUtils.findImgVideoUrl(jsonObjects.toString()));
				}
				imgUrl.addAll(WatermarkImgUtils.findImgVideoUrl(elevatorPartWorkVo.getRecordData().toJSONString()));
				elevatorPartWorkVo.setImgUrl(imgUrl);
			}
			allList.addAll(byList);
		}
		if (Func.isNotEmpty(allList)) {
			Map<String, List<ElevatorPartWorkVo>> yearGroup = allList.stream().collect(Collectors.groupingBy(e -> DateUtil.format(e.getCreateTime(), "yyyy")));
			List<String> yearList = new ArrayList<>(yearGroup.keySet());
			Collections.sort(yearList);
			Collections.reverse(yearList);
			yearList.forEach(e -> {
				List<ElevatorPartWorkVo> yearPlanList = yearGroup.get(e);
				Map<String, List<ElevatorPartWorkVo>> dayGroup = yearPlanList.stream().collect(Collectors.groupingBy(j -> DateUtil.format(j.getCreateTime(), "yyyy-MM-dd")));
				List<String> dayList = new ArrayList<>(dayGroup.keySet());
				Collections.sort(dayList);
				Collections.reverse(dayList);
				List<Map<String, Object>> dayGroupResult = new ArrayList<>();
				dayList.forEach(j -> {
					Map<String, Object> dayMap = new HashMap<>();
					dayMap.put("label", j);
					List<ElevatorPartWorkVo> dayItem = dayGroup.get(j);
					dayItem.sort(Comparator.comparing(ElevatorPartWorkVo::getCreateTime).reversed());
					dayMap.put("value", dayItem);
					dayGroupResult.add(dayMap);
				});
				Map<String, Object> yearMap = new HashMap<>();
				yearMap.put("label", e);
				yearMap.put("value", dayGroupResult);
				result.add(yearMap);
			});

		}
		resultMap.put("label", "保养工作(" + byCount + ")");
		resultMap.put("value", result);
		return resultMap;
	}

	@Override
	public Map<String, Object> selectElevatorFilesWxPlanWorkItem(Long elevatorId, Long partsId, String startDate, String endDate, Long floorStandIds) {
		Map<String, Object> resultMap = new HashMap<>();
		List<Map<String, Object>> result = new ArrayList<>();
		List<ElevatorPartWorkVo> allList = new ArrayList<>();
		int wxCount = baseMapper.getWorkListWxCount(elevatorId, partsId, floorStandIds);
		List<ElevatorPartWorkVo> wxList = baseMapper.getWorkListWx(elevatorId, partsId, floorStandIds, startDate, endDate);
		if (Func.isNotEmpty(wxList)) {
			wxList.forEach(e -> {
				// 封装故障现象信息
				List<String> problemNames = new ArrayList<>();
				if (StringUtil.isNotBlank(e.getProblemItem())) {
					List<String> problemKeys = Func.toStrList(e.getProblemItem());
					for (String problemKey : problemKeys) {
						String problemName = DictCache.getValue("fault_problem", problemKey);
						problemNames.add(problemName);
					}
				}
				if (StringUtil.isNotBlank(e.getProblemOtherDesc())) {
					problemNames.add(e.getProblemOtherDesc());
				}
				e.setProblemItemNames(problemNames);
			});
			allList.addAll(wxList);
		}
		if (Func.isNotEmpty(allList)) {
			Map<String, List<ElevatorPartWorkVo>> yearGroup = allList.stream().collect(Collectors.groupingBy(e -> DateUtil.format(e.getCreateTime(), "yyyy")));
			List<String> yearList = new ArrayList<>(yearGroup.keySet());
			Collections.sort(yearList);
			Collections.reverse(yearList);
			yearList.forEach(e -> {
				List<ElevatorPartWorkVo> yearPlanList = yearGroup.get(e);
				Map<String, List<ElevatorPartWorkVo>> dayGroup = yearPlanList.stream().collect(Collectors.groupingBy(j -> DateUtil.format(j.getCreateTime(), "yyyy-MM-dd")));
				List<String> dayList = new ArrayList<>(dayGroup.keySet());
				Collections.sort(dayList);
				Collections.reverse(dayList);
				List<Map<String, Object>> dayGroupResult = new ArrayList<>();
				dayList.forEach(j -> {
					Map<String, Object> dayMap = new HashMap<>();
					dayMap.put("label", j);
					List<ElevatorPartWorkVo> dayItem = dayGroup.get(j);
					dayItem.sort(Comparator.comparing(ElevatorPartWorkVo::getCreateTime).reversed());
					dayMap.put("value", dayItem);
					dayGroupResult.add(dayMap);
				});
				Map<String, Object> yearMap = new HashMap<>();
				yearMap.put("label", e);
				yearMap.put("value", dayGroupResult);
				result.add(yearMap);
			});

		}
		resultMap.put("label", "维修工作(" + wxCount + ")");
		resultMap.put("value", result);
		return resultMap;
	}

	@Override
	public Map<String, Object> selectElevatorFilesPjPlanWorkItem(Long elevatorId, Long partsId, String startDate, String endDate, Long floorStandIds) {
		Map<String, Object> resultMap = new HashMap<>();
		List<Map<String, Object>> result = new ArrayList<>();
		List<ElevatorPartWorkVo> allList = new ArrayList<>();
		int pjCount = baseMapper.getWorkListPjCount(elevatorId, partsId, floorStandIds);
		List<ElevatorPartWorkVo> pjList = baseMapper.getWorkListPj(elevatorId, partsId, floorStandIds, startDate, endDate);
		if (Func.isNotEmpty(pjList)) {
			allList.addAll(pjList);
		}
		if (Func.isNotEmpty(allList)) {
			Map<String, List<ElevatorPartWorkVo>> yearGroup = allList.stream().collect(Collectors.groupingBy(e -> DateUtil.format(e.getCreateTime(), "yyyy")));
			List<String> yearList = new ArrayList<>(yearGroup.keySet());
			Collections.sort(yearList);
			Collections.reverse(yearList);
			yearList.forEach(e -> {
				List<ElevatorPartWorkVo> yearPlanList = yearGroup.get(e);
				Map<String, List<ElevatorPartWorkVo>> dayGroup = yearPlanList.stream().collect(Collectors.groupingBy(j -> DateUtil.format(j.getCreateTime(), "yyyy-MM-dd")));
				List<String> dayList = new ArrayList<>(dayGroup.keySet());
				Collections.sort(dayList);
				Collections.reverse(dayList);
				List<Map<String, Object>> dayGroupResult = new ArrayList<>();
				dayList.forEach(j -> {
					Map<String, Object> dayMap = new HashMap<>();
					dayMap.put("label", j);
					List<ElevatorPartWorkVo> dayItem = dayGroup.get(j);
					dayItem.sort(Comparator.comparing(ElevatorPartWorkVo::getCreateTime).reversed());
					dayMap.put("value", dayItem);
					dayGroupResult.add(dayMap);
				});
				Map<String, Object> yearMap = new HashMap<>();
				yearMap.put("label", e);
				yearMap.put("value", dayGroupResult);
				result.add(yearMap);
			});

		}
		resultMap.put("value", result);
		resultMap.put("label", "配件工作(" + pjCount + ")");
		return resultMap;
	}

	@Override
	public List<PlanTemplateVO> workItemPreview(Long templateId, Long tltId) {
		List<PlanTemplateVO> templateVOS = new ArrayList<>();
		List<Long> templateIds = new ArrayList<>();
		templateIds.add(templateId);
		List<Long> tltIds = getTltIds(tltId, templateIds);
		templateIds.forEach(e -> {
			PlanTemplateVO planTemplateVO = new PlanTemplateVO();
			MaintainTemplate template = templateService.getById(e);
			planTemplateVO.setTemplateId(e);
			planTemplateVO.setTemplateName(template.getName());
			planTemplateVO.setWorkDay(template.getWorkDay());
			planTemplateVO.setWorkHour(template.getWorkHour());
			planTemplateVO.setWorkMin(template.getWorkMin());
			List<PlanTemplateTypeVO> planTemplateTypeVOS = baseMapper.selectPlanTemplateType(tltIds, e);
			planTemplateVO.setTemplateTypeVOS(change(planTemplateTypeVOS, e));
			templateVOS.add(planTemplateVO);
		});
		return templateVOS;
	}

	@Override
	public List<PlanDetailLocationTypeVO> getPlanLocationTypePreview(Long templateId) {
		List<Long> templateIds = new ArrayList<>();
		templateIds.add(templateId);
		List<PlanDetailLocationTypeVO> planDetailLocationTypeVOS = baseMapper.selectPlanDetailLocationType(templateIds);
		planDetailLocationTypeVOS.forEach(e -> {
			List<Long> tltChildrenIds = getTltIds(e.getTltId(), templateIds);
			Integer workItemCount = baseMapper.selectPlanWorItemCount(tltChildrenIds, templateIds);
			e.setWorkItemCount(workItemCount);
		});
		// 过滤关联工作项为0的分类
		planDetailLocationTypeVOS = planDetailLocationTypeVOS.stream().filter(e -> e.getWorkItemCount() > 0).collect(Collectors.toList());
		return planDetailLocationTypeVOS;
	}

	@Override
	public List<Long> getFromPlanIdByOwnId(Long planId) {
		return baseMapper.getFromPlanIdByOwnId(planId);
	}


	/**
	 * 查询事务工单列表
	 *
	 * @param planContentSearchDTO
	 * @param type
	 * @return
	 */
	private List<PlanContentElevatorVo> getPlanAffairList(PlanContentSearchDTO planContentSearchDTO, Integer type) {
		PlanContentSearchDTO planContentSearchDTO2 = new PlanContentSearchDTO();
		planContentSearchDTO2.setUserId(planContentSearchDTO.getUserId());
		planContentSearchDTO2.setBeginTime(planContentSearchDTO.getBeginTime());
		planContentSearchDTO2.setEndTime(planContentSearchDTO.getEndTime());

		if (type.equals(PLAN_TYPE[1])) {
			planContentSearchDTO2.setPlanStatus(TaskStatusEnum.SW_TO_START.getStatus());
			planContentSearchDTO2.setBeginTime(DateUtil.offsetDay(new Date(), -365));
			planContentSearchDTO2.setEndTime(DateUtil.endOfDay(DateUtil.yesterday()));
		} else if (type.equals(PLAN_TYPE[2])) {
			planContentSearchDTO2.setPlanStatus(TaskStatusEnum.SW_UNDER_WAY.getStatus());
		} else if (type.equals(PLAN_TYPE[3])) {
			planContentSearchDTO2.setPlanStatus(TaskStatusEnum.SW_SIGN_FINISH.getStatus());
		}
		List<PlanContentElevatorVo> elevatorVoList = baseMapper.planAffairList(planContentSearchDTO2, AuthUtil.getTenantId());
		for (PlanContentElevatorVo planContentElevatorVo : elevatorVoList) {
			planContentElevatorVo.setStatusName(TaskStatusEnum.getTaskName(MaintainPlanContentEnum.MAINTAIN_AFFAIR.getId(), planContentElevatorVo.getStatus()));
		}
		return elevatorVoList;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean byOfflineUpdate(ByPlanOfflineDetailDTO dto) {

		ByPlanOfflineDetailDTO copy = new ByPlanOfflineDetailDTO();
		BeanUtil.copyProperties(dto, copy);

		MaintainPlanContent planContent = super.getById(dto.getPlanId());
		if (planContent == null) {
			throw new ServiceException("工单id错误=" + dto.getPlanId());
		}

		if (planContent.getStatus().equals(TaskStatusEnum.BY_FINISH.getStatus()) || planContent.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus()) || planContent.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())) {
			return Boolean.TRUE;
		}
		MaintainPlanContentExt planContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, dto.getPlanId()));
		List<MaintainCheckHistory> checkHistories = checkHistoryService.listByPlanId(dto.getPlanId());

		// 处理工作项记录数据同步
		// 当线上历史数据表为空时
		if (Func.isEmpty(checkHistories)) {
			dto.getCheckHistories().forEach(e -> {
				e.setTltNames(e.getTltNames().replace("&amp;&amp;", "&&"));
				e.setTenantId(AuthUtil.getTenantId());
			});
			checkHistoryService.saveBatch(dto.getCheckHistories());
			dto.getCheckHistories().forEach(e -> {
				if (Func.isNotEmpty(e.getCheckRecords())) {
					e.getCheckRecords().forEach(j -> {
						j.setCheckHistoryId(e.getId());
						j.setTenantId(AuthUtil.getTenantId());
					});
					checkRecordService.saveBatch(e.getCheckRecords());
				}
			});
		} else {

			Map<Long, List<MaintainCheckHistory>> contentMap = checkHistories.stream().collect(Collectors.groupingBy(MaintainCheckHistory::getTemplateContentId));
			List<MaintainCheckRecord> recordsResult = new ArrayList<>();
			// 过滤需要同步的工作项数据
			List<MaintainCheckHistory> contentResult = dto.getCheckHistories().stream().filter(e -> {

				e.setTltNames(e.getTltNames().replace("&amp;&amp;", "&&"));
				e.setTenantId(AuthUtil.getTenantId());

				// 该工作项不存在于线上历史记录时 直接插入
				if (!contentMap.containsKey(e.getTemplateContentId())) {
					return Boolean.TRUE;
				}
				MaintainCheckHistory onlineContent = contentMap.get(e.getTemplateContentId()).get(0);
				JSONObject onlineRecordData = onlineContent.getRecordData();
				// 判断工作项内容是否为图片或者视频
				if (onlineRecordData.getInteger("type").equals(3) || onlineRecordData.getInteger("type").equals(4)) {
					return Boolean.TRUE;
				}
				// 判断工作项修改时间
				if (e.getUpdateTime().getTime() > onlineContent.getUpdateTime().getTime()) {
					return Boolean.TRUE;
				}

				if (Func.isNotEmpty(e.getCheckRecords())) {
					recordsResult.addAll(e.getCheckRecords());
				}

				return Boolean.FALSE;
			}).collect(Collectors.toList());
			// 处理需要同步的工作项数据
			contentResult.forEach(e -> {
				if (contentMap.containsKey(e.getTemplateContentId())) {
					MaintainCheckHistory onlineContent = contentMap.get(e.getTemplateContentId()).get(0);
					if (onlineContent.getTemplateId().equals(e.getTemplateId())) {
						e.setId(onlineContent.getId());
						JSONObject onlineRecordData = onlineContent.getRecordData();
						// 判断工作项内容是否为图片或者视频
						if (onlineRecordData.getInteger("type").equals(3) || onlineRecordData.getInteger("type").equals(4)) {
							JSONObject offlineRecordData = e.getRecordData();
							JSONArray offlineRecordDataVal = offlineRecordData.getJSONArray("val");
							if (!onlineRecordData.containsKey("val")) {
								onlineRecordData.put("val", new JSONArray());
							}
							JSONArray onlineRecordDataVal = onlineRecordData.getJSONArray("val");
							if (Func.isNotEmpty(offlineRecordDataVal) && Func.isNotEmpty(onlineRecordDataVal)) {

								for (int i = 0; i < offlineRecordDataVal.size(); i++) {
									JSONObject j = offlineRecordDataVal.getJSONObject(i);
									boolean t = Boolean.TRUE;
									for (int k = 0; k < onlineRecordDataVal.size(); k++) {
										if (j.getString("url").equals(onlineRecordDataVal.getJSONObject(k).getString("url"))) {
											t = Boolean.FALSE;
										}
									}
									if (t) {
										onlineRecordData.getJSONArray("val").add(j);
									}
								}
							} else {
								onlineRecordData.getJSONArray("val").addAll(offlineRecordDataVal);
							}
//							onlineRecordData.getJSONArray("val").addAll(offlineRecordDataVal);
							e.setRecordData(onlineRecordData);
						}
					}
				}
			});
			// 插入或更新工作项记录
			checkHistoryService.saveOrUpdateBatch(contentResult);

			// 插入对应工作项操作记录
			contentResult.forEach(e -> {
				if (Func.isNotEmpty(e.getCheckRecords())) {
					e.getCheckRecords().forEach(j -> {
						j.setCheckHistoryId(e.getId());
					});
					recordsResult.addAll(e.getCheckRecords());
//					e.getCheckRecords().forEach(j -> {
//						j.setTenantId(AuthUtil.getTenantId());
//						j.setCheckHistoryId(e.getId());
//					});
//					checkRecordService.saveBatch(e.getCheckRecords());
				}
			});
			if (Func.isNotEmpty(recordsResult)) {
				List<MaintainCheckRecord> finalRecordsResult = recordsResult.stream().filter(e -> Func.isNotEmpty(e.getCheckHistoryId())).collect(Collectors.toList());
				finalRecordsResult.forEach(e -> e.setTenantId(AuthUtil.getTenantId()));
				List<List<MaintainCheckRecord>> p = ListUtil.partition(finalRecordsResult, 20);
				p.forEach(e -> checkRecordService.saveBatch(e));
			}

		}

		// 插入工单追踪日志
		if (Func.isNotEmpty(dto.getLogList())) {
			dto.getLogList().forEach(e -> {
				e.setExecutorId(AuthUtil.getUserId());
				e.setExecutor(AuthUtil.getNickName());
				e.setTenantId(AuthUtil.getTenantId());
			});
			malfunctionLogService.saveBatch(dto.getLogList());
		}

		// 插入签到记录
		if (Func.isNotEmpty(dto.getSignList())) {
			dto.getSignList().forEach(e -> {
				e.setTenantId(AuthUtil.getTenantId());
				// 处理单签退数据
				if (Func.isEmpty(e.getSignTime()) && Func.isNotEmpty(e.getSignOutTime())) {
					MaintainSign sign = signService.getOne(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, dto.getPlanId())
						.eq(MaintainSign::getUserId, AuthUtil.getUserId()).isNull(MaintainSign::getSignOutTime).orderByDesc(MaintainSign::getCreateTime), Boolean.FALSE);
					if (Func.isNotEmpty(sign)) {
						sign.setSignOutStatus(e.getSignOutStatus());
						sign.setSignOutTime(e.getSignOutTime());
						sign.setSignOutImage(e.getSignOutImage());
						BeanUtil.copyProperties(sign, e);
					}
				}
				if (Func.isNotEmpty(e.getSignTime()) && Func.isNotEmpty(e.getSignOutTime())) {
					e.setTimeInterval(DateUtil.between(e.getSignTime(), e.getSignOutTime(), DateUnit.MINUTE));
				}
				if (Func.isNotEmpty(e.getSignTime()) && Func.isEmpty(e.getSignOutTime())) {
					List<MaintainSign> signList = signService.listByPlanUserNotSignOut(dto.getPlanId(), AuthUtil.getUserId());
					if (Func.isNotEmpty(signList)) {
						signList.forEach(s -> {
							s.setSignOutStatus(SignOutStatusEnum.NORMAL.getId());
							s.setStatus(SignStatusEnum.SYSTEM.getId());
							s.setSignOutTime(new Date());
							s.setTimeInterval(0L);
							signService.updateById(s);
							// 插入任务记录
							User user = userService.getById(s.getUserId());
							PlanLogDTO planLogDTO = new PlanLogDTO();
							planLogDTO.setSignId(s.getId());
							planLogDTO.setExpDesc(WorkTrackStatusEnum.SYSTEM_SIGN.getTypeName());
							malfunctionLogService.insertWorkLog(s.getPlanId(), WorkTrackStatusEnum.SIGN_OUT.getTypeName(), TaskStatusEnum.BY_PROCESSED.getStatus(), JSONObject.toJSONString(planLogDTO), AuthUtil.getUserId(), user.getRealName());
							planContentUserService.updatePlanUserSignInfo(s.getPlanId(), SignEnum.SIGN_OUT.getId(), s.getUserId(), s.getSignOutStatus());
						});
					}
				}
			});
			List<MaintainSign> resultSign = dto.getSignList().stream().filter(e -> Func.isNotEmpty(e.getSignTime())).collect(Collectors.toList());
			signService.saveOrUpdateBatch(resultSign);
		}

		// 同步签字数据
		if (Func.isNotEmpty(dto.getSigntures())) {
			dto.getSigntures().forEach(e -> {
				e.setTenantId(AuthUtil.getTenantId());
			});
			signtureService.saveBatch(dto.getSigntures());
		}

		// 当线上工单状态为维保签字时
		if (planContent.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())) {
			// 离线工单状态为已完成
			if (dto.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())) {
				// 更新工单状态
				planContent.setStatus(dto.getStatus());
				// 更新工单完成时间
				planContentExt.setPlanEndTime(dto.getPlanEndTime());
			}

			planContentUserService.updatePlanUserSignInfo(dto.getPlanId(), SignEnum.SIGN_OUT.getId(), AuthUtil.getUserId(), 3);
		}

		// 当线上工单状态为已提交时
		if (planContent.getStatus().equals(TaskStatusEnum.BY_FINISH.getStatus())) {
			// 离线工单状态为已完成
			if (dto.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())) {
				// 更新工单状态
				planContent.setStatus(dto.getStatus());
				// 更新工单完成时间
				planContentExt.setPlanEndTime(dto.getPlanEndTime());
				// 更新工单维保签字时间
				planContentExt.setMaintainSignatureTime(dto.getMaintainSignatureTime());
			}
			// 离线工单状态为维保完成
			if (dto.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())) {
				// 更新工单状态
				planContent.setStatus(dto.getStatus());
				// 更新工单维保签字时间
				planContentExt.setMaintainSignatureTime(dto.getMaintainSignatureTime());
			}

			planContentUserService.updatePlanUserSignInfo(dto.getPlanId(), SignEnum.SIGN_OUT.getId(), AuthUtil.getUserId(), 3);
		}

		// 当线上工单状态为进行中时
		if (planContent.getStatus().equals(TaskStatusEnum.BY_PROCESSED.getStatus())) {

			// 离线工单状态为进行中
			if (dto.getStatus().equals(TaskStatusEnum.BY_PROCESSED.getStatus())) {
				if (Func.isNotEmpty(dto.getSignList())) {
					MaintainSign sign = dto.getSignList().get(dto.getSignList().size() - 1);
					if (Func.isNotEmpty(sign.getSignTime()) && Func.isEmpty(sign.getSignOutTime())) {
						planContentUserService.updatePlanUserSignInfo(dto.getPlanId(), SignEnum.SIGN.getId(), AuthUtil.getUserId(), 3);
					} else {
						planContentUserService.updatePlanUserSignInfo(dto.getPlanId(), SignEnum.SIGN_OUT.getId(), AuthUtil.getUserId(), 3);
					}
				}
			}

			// 离线工单状态不为待开始 且不为进行中
			if (!dto.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus()) && !dto.getStatus().equals(TaskStatusEnum.BY_PROCESSED.getStatus())) {
				// 更新工单状态
				planContent.setStatus(dto.getStatus());
				// 更新工单完成时间
				planContentExt.setPlanEndTime(dto.getPlanEndTime());
				// 更新工单维保签字时间
				planContentExt.setMaintainSignatureTime(dto.getMaintainSignatureTime());

				// 系统代签
				signService.checkUserSignOut(dto.getPlanId());

				// 计算工单作业耗时
				List<MaintainSign> list = signService.list(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, dto.getPlanId()).orderByDesc(MaintainSign::getCreateTime));
				Long timeInterval = 0L;
				if (planContent.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_BY.getId()) {
					for (MaintainSign maintainSign : list) {
						timeInterval = timeInterval + Convert.toInt(maintainSign.getTimeInterval(), 0);
					}
				} else if (planContent.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_WX.getId()) {
					if (list.size() > 0) {
						MaintainSign maintainSign = list.get(0);
						timeInterval = DateUtil.between(maintainSign.getCreateTime(), new Date(), DateUnit.MINUTE);
					}
				}
				planContentExt.setWorkMinute(Convert.toInt(timeInterval));

				if (dto.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())) {
					planContentExt.setOverdueDay(DateUtil.betweenDay(planContent.getPlanDate(), new Date(), true) == 0 ? null : 1);
				}

				planContentUserService.updatePlanUserSignInfo(dto.getPlanId(), SignEnum.SIGN_OUT.getId(), AuthUtil.getUserId(), 3);
			}
		}

		// 当线上工单状态为待开始时
		if (planContent.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())) {
			// 离线工单状态不为待开始
			if (!dto.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())) {
				// 更新工单状态
				planContent.setStatus(dto.getStatus());
				// 更新工单开始时间
				planContentExt.setPlanBeginTime(dto.getPlanBeginTime());
				// 更新工单完成时间
				planContentExt.setPlanEndTime(dto.getPlanEndTime());
				// 更新工单维保签字时间
				planContentExt.setMaintainSignatureTime(dto.getMaintainSignatureTime());

				MaintainSign sign = dto.getSignList().get(dto.getSignList().size() - 1);
				if (Func.isNotEmpty(sign.getSignTime()) && Func.isEmpty(sign.getSignOutTime())) {
					planContentUserService.updatePlanUserSignInfo(dto.getPlanId(), SignEnum.SIGN.getId(), AuthUtil.getUserId(), 3);
				} else {
					planContentUserService.updatePlanUserSignInfo(dto.getPlanId(), SignEnum.SIGN_OUT.getId(), AuthUtil.getUserId(), 3);
				}
			}
		}

		if (Func.isNotEmpty(dto.getFinishDate())) {
			planContent.setFinishDate(dto.getFinishDate());
		}

		// 清理工单废弃图片
		planHistoryImageService.removeByPlan(planContent.getId());

		return super.updateById(planContent) && maintainPlanContentExtService.updateById(planContentExt);
	}


	/**
	 * 查询质检工单列表
	 *
	 * @param planContentSearchDTO
	 * @param type
	 * @return
	 */
	private List<PlanContentElevatorVo> getPlanCheckList(PlanContentSearchDTO planContentSearchDTO, Integer type) {
		PlanContentSearchDTO planContentSearchDTO2 = new PlanContentSearchDTO();
		planContentSearchDTO2.setUserId(planContentSearchDTO.getUserId());
		planContentSearchDTO2.setBeginTime(planContentSearchDTO.getBeginTime());
		planContentSearchDTO2.setEndTime(planContentSearchDTO.getEndTime());

		if (type.equals(PLAN_TYPE[1])) {
			planContentSearchDTO2.setPlanStatus(TaskStatusEnum.ZJ_TO_START.getStatus());
			planContentSearchDTO2.setBeginTime(DateUtil.offsetDay(new Date(), -365));
			planContentSearchDTO2.setEndTime(DateUtil.endOfDay(DateUtil.yesterday()));
		} else if (type.equals(PLAN_TYPE[2])) {
			planContentSearchDTO2.setPlanStatus(TaskStatusEnum.ZJ_UNDER_WAY.getStatus());
		} else if (type.equals(PLAN_TYPE[3])) {
			planContentSearchDTO2.setPlanStatus(TaskStatusEnum.ZJ_SIGN_FINISH.getStatus());
		}
		List<PlanContentElevatorVo> elevatorVoList = baseMapper.planCheckList(planContentSearchDTO2, AuthUtil.getTenantId());
		for (PlanContentElevatorVo planContentElevatorVo : elevatorVoList) {
			planContentElevatorVo.setStatusName(TaskStatusEnum.getTaskName(MaintainPlanContentEnum.MAINTAIN_CHECK.getId(), planContentElevatorVo.getStatus()));
		}
		return elevatorVoList;
	}


	/**
	 * 获取工单执行人的用户列表
	 *
	 * @param planContentElevatorVos
	 */
	private Map<Long, List<User>> getPlanUserList(List<PlanContentElevatorVo> planContentElevatorVos) {
		//批量查询人员
		List<String> userIdss = planContentElevatorVos.stream().map(PlanContentElevatorVo::getUserIds).collect(Collectors.toList());
		List<String> resultUserIds = new ArrayList<>(50);
		for (String userIds : userIdss) {
			List<String> list = Arrays.asList(userIds.split(","));
			resultUserIds.addAll(list);
		}
		List<String> userIds = resultUserIds.stream().distinct().collect(Collectors.toList());
		if (userIds.size() == 0) {
			return new HashMap<>();
		}
		List<User> userList = userService.listByIds(userIds);
		return userList.stream().collect(Collectors.groupingBy(User::getId));
	}

	/**
	 * 根据ids筛选人员
	 *
	 * @param userMap
	 * @param userIds
	 */
	private List<User> getPlanUsers(Map<Long, List<User>> userMap, List userIds) {
		List<User> resultList = new ArrayList<>(16);
		for (Object userId : userIds) {
			List<User> users = userMap.get(Convert.toLong(userId));
			resultList.addAll(users);
		}
		return resultList;
	}

	@Override
	public IPage<PlanOrderHomePageVO> planOrderHomePage(PlanOrderHomePageSearchDTO searchDTO, IPage<PlanOrderHomePageVO> page) {
		searchDTO.setCurUserId(AuthUtil.getUserId());
		List<PlanOrderHomePageVO> pageList = baseMapper.planOrderHomePage(searchDTO, page);
//		Date serviceDate = DateUtil.date();
//		for (PlanOrderHomePageVO planOrderItem : pageList) {
//			switch (planOrderItem.getTypeStatus()) {
//				case 1: {
//					List<MaintainTemplate> maintainTemplateList = maintainPlanTemplateService.listPlanTemplate(planOrderItem.getId());
//					planOrderItem.setMaintainTemplates(maintainTemplateList);
//					break;
//				}
//				case 2: {
//					MaintainMalfunctionWork wxDetail = wxPlanOrderDetail(planOrderItem.getId());
//					planOrderItem.setProblemItemNames(wxDetail != null ? wxDetail.getProblemItemNames() : null);
//					break;
//				}
//				case 3: {
//					planOrderItem.setServiceDate(serviceDate);
//					MaintainMalfunctionRescue malfunctionRescue = maintainMalfunctionRescueService.getOne(Wrappers.<MaintainMalfunctionRescue>lambdaQuery().eq(MaintainMalfunctionRescue :: getPlanId, planOrderItem.getId()), false);
//					if (Func.isNotEmpty(malfunctionRescue)) {
//						planOrderItem.setTrapType(malfunctionRescue.getTrapType());
//						planOrderItem.setTrapDesc(malfunctionRescue.getTrapDesc());
//					}
//					break;
//				}
//				case 4: {
//					MaintainPartsWork maintainPartsWork = maintainPartsWorkService.getOne(Wrappers.<MaintainPartsWork>lambdaQuery().eq(MaintainPartsWork :: getPlanId, planOrderItem.getId()), false);
//					if (Func.isNotEmpty(maintainPartsWork)) {
//						planOrderItem.setPartsName(maintainPartsWork.getPartsName());
//						planOrderItem.setPartsNum(maintainPartsWork.getNum());
//					}
//					break;
//				}
//				case 5: {
//					MaintainPlanAffair maintainPlanAffair = maintainPlanAffairService.getOne(Wrappers.<MaintainPlanAffair>lambdaQuery().eq(MaintainPlanAffair :: getPlanId, planOrderItem.getId()), false);
//					if (Func.isNotEmpty(maintainPlanAffair)) {
//						planOrderItem.setAffairDesc(maintainPlanAffair.getPlanDesc());
//						planOrderItem.setEmerProcType(maintainPlanAffair.getEmerProcType());
//					}
//					break;
//				}
//				case 6: {
//					MaintainPlanCheck maintainPlanCheck = maintainPlanCheckService.getOne(Wrappers.<MaintainPlanCheck>lambdaQuery().eq(MaintainPlanCheck :: getPlanId, planOrderItem.getId()), false);
//					if (Func.isNotEmpty(maintainPlanCheck)) {
//						planOrderItem.setAffairDesc(maintainPlanCheck.getPlanDesc());
//						planOrderItem.setCheckType(maintainPlanCheck.getCheckType());
//					}
//					break;
//				}
//				default: break;
//			}
//		}
		return page.setRecords(pageList);
	}

	@Override
	public IPage<PlanHomeDataVO> planOrderHomePageV3(PlanOrderHomePageSearchDTO searchDTO, IPage<PlanHomeDataVO> page) {
		searchDTO.setCurUserId(AuthUtil.getUserId());
		List<PlanHomeDataVO> pageList = baseMapper.planOrderHomePageV3(searchDTO, page);
		if (Func.isEmpty(pageList)) {
			return page.setRecords(pageList);
		}

		String planIds = pageList.stream().map(PlanHomeDataVO::getPlanIds).collect(Collectors.joining(","));
		List<PlanOrderHomePageVO> orderList = baseMapper.planOrderByIds(planIds, AuthUtil.getUserId());
		Map<String, List<PlanOrderHomePageVO>> orderMap = null;
		if (searchDTO.getOrder() != null && searchDTO.getOrder() == 0) {
			orderMap = orderList.stream().collect(Collectors.groupingBy(t -> DateUtil.formatDate(t.getPlanDate())));
		} else {
			orderMap = orderList.stream().collect(Collectors.groupingBy(t -> String.valueOf(t.getBuildingId())));
		}
		for (PlanHomeDataVO pageData : pageList) {
			pageData.setPlanList(orderMap.get(pageData.getGroupId()));
		}

		return page.setRecords(pageList);
	}

	@Override
	public List<MaintainPlanContentTypeCountVo> planOrderHomeTypeStatistics(PlanOrderHomePage4SearchDTO planContentSearchDTO) {
		PlanContentSearchDTO searchDTO = new PlanContentSearchDTO();
		searchDTO.setBeginTime(DateUtil.parseDateTime(planContentSearchDTO.getBeginTime()));
		searchDTO.setEndTime(DateUtil.parseDateTime(planContentSearchDTO.getEndTime()));
		searchDTO.setTypeStatus(planContentSearchDTO.getTypeStatus());
		searchDTO.setUserId(planContentSearchDTO.getUserId());
		// 今日，查询包含历史未完成的工单（暂定查询历史一年的工单，保养查7天）
//		if (planContentSearchDTO.isToday()) {
//			searchDTO.setBeginTime2(DateUtil.beginOfDay(DateUtil.offsetDay(new Date(), -365)));
//			searchDTO.setEndTime2(DateUtil.endOfDay(DateUtil.yesterday()));
//			// 针对保养工单，只统计最近7天的数据
//			searchDTO.setPlanDateBeginTime(DateUtil.beginOfDay(DateUtil.offsetDay(new Date(), -7)));
//		}
		return getplanContentType(searchDTO);
	}

	@Override
	public IPage<PlanHomeV4DataVO> planOrderHomePageV4(PlanOrderHomePage4SearchDTO searchDTO, IPage<PlanHomeV4DataVO> page) {
		List<PlanHomeV4DataVO> pageList = baseMapper.planOrderHomePageV4(searchDTO, page);
		if (Func.isEmpty(pageList)) {
			return page.setRecords(pageList);
		}

		List<Long> planIds = pageList.stream()
			.flatMap(vo -> Arrays.stream(vo.getPlanIds().split(",")))
			.filter(StrUtil::isNotBlank)
			.map(Long::valueOf)
			.collect(Collectors.toList());
		List<PlanOrderHomePageV4VO> allOrderList = baseMapper.planOrderV4ByIds(planIds, searchDTO.getUserId());
		Map<String, List<PlanOrderHomePageV4VO.BuildingVO>> map = allOrderList.stream().collect(Collectors.toMap(PlanOrderHomePageV4VO::getPlanDateGroup, PlanOrderHomePageV4VO::getBuildingList));
		for (PlanHomeV4DataVO item : pageList) {
			List<PlanOrderHomePageV4VO.BuildingVO> orderList = map.get(item.getPlanDate()).stream().sorted(Comparator.comparing(PlanOrderHomePageV4VO.BuildingVO::getOrderNum).reversed()).collect(Collectors.toList());
			// 拼接工单数量
			item.setPlanDate(String.format("%s(%d)", item.getPlanDate(), orderList.stream().flatMapToInt(t -> IntStream.of(t.getList().size())).sum()));
			item.setMaintainPlanContentListVos(orderList);
			item.setPlanIds(null);

			for (PlanOrderHomePageV4VO.BuildingVO workItem : orderList) {
				// 计算用户与项目距离
				if (StrUtil.isNotEmpty(searchDTO.getLatitude()) && StrUtil.isNotEmpty(searchDTO.getLongitude())) {
					BigDecimal distance = DistanceUtils.getDistance(Convert.toDouble(searchDTO.getLongitude()), Convert.toDouble(searchDTO.getLatitude()), Convert.toDouble(workItem.getLongitude()), Convert.toDouble(workItem.getLatitude()));
					final String kmDesc = distance.divide(Convert.toBigDecimal(1000), 1, RoundingMode.HALF_UP).toString();
					workItem.setKmDesc(kmDesc + "km");
				}
			}

			map.put(item.getPlanDate(), orderList);
		}

		return page.setRecords(pageList);
	}

	@Override
	public List<PlanFinishOrderHomePageV4VO> planOrderHomeFinishPageV4(PlanOrderHomePage4SearchDTO searchDTO) {
		List<PlanFinishOrderHomePageV4VO> finishList = baseMapper.getFinishPlanListV4(searchDTO, AuthUtil.getTenantId());
		for (PlanFinishOrderHomePageV4VO item : finishList) {
			for (PlanFinishOrderHomePageV4VO.PlanWorkItemList planWorkItemList : item.getList()) {
				// 剔除未参与工单的人员
				if (planWorkItemList.getSignUsers() != null) {
					planWorkItemList.setSignUsers(planWorkItemList.getSignUsers().stream().filter(PlanOrderHomeUserVO::getIsTakePartIn).collect(Collectors.toCollection(LinkedList::new)));
				}

				// 计算逾期标签
				if (planWorkItemList.getTypeStatus() == MaintainPlanContentEnum.MAINTAIN_BY.getId() && AUDIT_TYPE[2].equals(planWorkItemList.getAuditType())) {
					if (planWorkItemList.getMaintainSignatureTime() != null && planWorkItemList.getOverdueDate() != null) {
						if (planWorkItemList.getMaintainSignatureTime().after(planWorkItemList.getOverdueDate())) {
							planWorkItemList.setTimeliness("逾期" + DateUtil.betweenDay(planWorkItemList.getMaintainSignatureTime(), planWorkItemList.getOverdueDate(), true) + "天");
						}
					}
				}
			}
		}
		return finishList;
	}

	/**
	 * 保养工单详情
	 *
	 * @param planId
	 * @return
	 */
	private ByPlanOrderDetailVO byPlanOrderDetail(Long planId) {
		ByPlanOrderDetailVO byPlanOrderDetail = baseMapper.selectByPlanOrderDetail(planId);
		if (Func.isEmpty(byPlanOrderDetail)) {
			return byPlanOrderDetail;
		}

		Date curDate = new Date();
		// 超时
		long days = DateUtil.betweenDay(byPlanOrderDetail.getPlanDate(), curDate, true);
		if (days > 0) {
			byPlanOrderDetail.setTimeliness("超时" + days + "天");
		}

		// 逾期
		if (Func.equalsSafe(2, byPlanOrderDetail.getAuditType())) {
			// 若无签字时间，则取当前时间
			Date signDate = Func.isEmpty(byPlanOrderDetail.getMaintainSignatureTime()) ? curDate : byPlanOrderDetail.getMaintainSignatureTime();
			long overdueDay = DateUtil.betweenDay(byPlanOrderDetail.getOverdueDate(), signDate, true);
			if (overdueDay > 0) {
				byPlanOrderDetail.setOverdueName("逾期" + overdueDay + "天");
			}
		}

		return byPlanOrderDetail;
	}

	/**
	 * 维修工单详情
	 *
	 * @param planId
	 * @return
	 */
	private MaintainMalfunctionWork wxPlanOrderDetail(Long planId) {
		// 查询维修详情
		MaintainMalfunctionWork malfunctionWork = maintainMalfunctionWorkService.getOne(Wrappers.<MaintainMalfunctionWork>lambdaQuery().eq(MaintainMalfunctionWork::getPlanId, planId).orderByAsc(MaintainMalfunctionWork::getId), false);
		if (Func.isEmpty(malfunctionWork)) {
			return malfunctionWork;
		}

		// 封装故障现象信息
		if (StringUtil.isNotBlank(malfunctionWork.getProblemItem())) {
			List<String> problemKeys = Func.toStrList(malfunctionWork.getProblemItem());
			List<String> problemNames = new ArrayList<>();
			for (String problemKey : problemKeys) {
				String problemName = DictCache.getValue("fault_problem", problemKey);
				problemNames.add(problemName);
			}
			malfunctionWork.setProblemItemNames(problemNames);
		}
		return malfunctionWork;
	}

	@Override
	public List<PlanContentElevatorVo> getOldOfflineByPlanList() {
		//设置维修保养的查询条件
		PlanContentSearchDTO planContentSearchDTO = new PlanContentSearchDTO();
		planContentSearchDTO.setBeginTime(DateUtil.beginOfDay(DateUtil.lastMonth()));
		planContentSearchDTO.setEndTime(DateUtil.endOfDay(DateUtil.date()));
		List<Integer> statusList = new ArrayList<>(5);
		statusList.add(TaskStatusEnum.BY_DISABLE.getStatus());
		statusList.add(TaskStatusEnum.BY_PROCESSED.getStatus());
		statusList.add(TaskStatusEnum.BY_FINISH.getStatus());
		statusList.add(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus());
		planContentSearchDTO.setStatusList(statusList);
		planContentSearchDTO.setUserId(AuthUtil.getUserId());
		planContentSearchDTO.setTypeStatus(MaintainPlanContentEnum.MAINTAIN_BY.getId());
		List<PlanContentElevatorVo> planContentElevatorList = baseMapper.selectMaintainPlanContent(planContentSearchDTO, AuthUtil.getTenantId()).stream().limit(20).collect(Collectors.toList());
		for (PlanContentElevatorVo planOrder : planContentElevatorList) {
			// 工作项
			List<PlanTemplateVO> planTemplateList = this.getPlanWorkItem(planOrder.getPlanId(), null, null);
			planOrder.setPlanTemplateList(planTemplateList);
			// 工作项统计
			Map<String, Object> planLocationTypeList = this.getPlanLocationType(planOrder.getPlanId());
			planOrder.setPlanLocationTypeList(planLocationTypeList);
		}
		return planContentElevatorList;
	}

	@Override
	public List<OfflineByPlanListVO> getOfflineByPlanList() {
		// 查询今天及历史一个月内未完成的保养工单
		PlanOrderHomePageSearchDTO search = new PlanOrderHomePageSearchDTO();
		search.setCurUserId(AuthUtil.getUserId());
		search.setTypeStatus(MaintainPlanContentEnum.MAINTAIN_BY.getId());
		search.setStartDate(DateUtil.formatDate(DateUtil.lastMonth()));
		search.setEndDate(DateUtil.today());
		search.setTenantId(AuthUtil.getTenantId());
		List<PlanOrderHomePageVO> pageList = baseMapper.planOrderHomePage(search, null).stream().limit(20).collect(Collectors.toList());

		List<OfflineByPlanListVO> offlineByPlanList = new ArrayList<>();
		for (PlanOrderHomePageVO planOrder : pageList) {
			OfflineByPlanListVO offlineByPlan = new OfflineByPlanListVO();
			BeanUtils.copyProperties(planOrder, offlineByPlan);
			// 工单详情
			ByPlanOrderDetailVO planDetail = byPlanOrderDetail(planOrder.getId());
			BeanUtils.copyProperties(planDetail, offlineByPlan);
			// 工作项
			List<PlanTemplateVO> planTemplateList = this.getPlanWorkItem(planOrder.getId(), null, null);
			offlineByPlan.setPlanTemplateList(planTemplateList);
			// 工作项统计
			Map<String, Object> planLocationTypeList = this.getPlanLocationType(planOrder.getId());
			offlineByPlan.setPlanLocationTypeList(planLocationTypeList);
			offlineByPlanList.add(offlineByPlan);
		}

		return offlineByPlanList;
	}

	@Override
	public ElevatorRescueRobotSimpleVO getElevatorSimpleInfoByPlanId(Long planId) {
		return baseMapper.getElevatorSimpleInfoByPlanId(planId);
	}

	@Override
	public Map<String, Long> selectPlanUserOverdueCount() {
		Map<String, Long> resultMap = new HashMap<>();
		// 即将逾期
		resultMap.put("beOverdue", 0L);
		// 已逾期
		resultMap.put("inOverdue", 0L);
		// 本人未签
		resultMap.put("self", 0L);
		// 他人未签
		resultMap.put("others", 0L);
		List<ElevatorPlanUserDTO> userDTOS = baseMapper.selectPlanUserOverdueCount(AuthUtil.getUserId());
		if (Func.isNotEmpty(userDTOS)) {
			// 即将逾期
			resultMap.put("beOverdue", userDTOS.stream().filter(e -> (e.getPlanStatus() == TaskStatusEnum.BY_DISABLE.getStatus()
				|| e.getPlanStatus() == TaskStatusEnum.BY_PROCESSED.getStatus()
				|| e.getPlanStatus() == TaskStatusEnum.BY_FINISH.getStatus())
				&& Func.isNotEmpty(e.getOverdueType()) && e.getOverdueType() == 2).map(ElevatorPlanUserDTO::getPlanId).distinct().count());
			// 已逾期
			resultMap.put("inOverdue", userDTOS.stream().filter(e -> (e.getPlanStatus() == TaskStatusEnum.BY_DISABLE.getStatus()
				|| e.getPlanStatus() == TaskStatusEnum.BY_PROCESSED.getStatus()
				|| e.getPlanStatus() == TaskStatusEnum.BY_FINISH.getStatus())
				&& Func.isNotEmpty(e.getOverdueType()) && e.getOverdueType() == 3).map(ElevatorPlanUserDTO::getPlanId).distinct().count());
			// 本人未签
			resultMap.put("self", userDTOS.stream().filter(e -> e.getSelfSignatureCount() == 0 && e.getPlanStatus() == TaskStatusEnum.BY_FINISH.getStatus()).map(ElevatorPlanUserDTO::getPlanId).distinct().count());
			// 他人未签
			resultMap.put("others", userDTOS.stream().filter(e -> e.getPlanUserCount() > 1 && (e.getOthersSignatureCount() == 0 || (e.getOthersSignatureCount() != 0 && e.getOthersSignatureCount() < (e.getPlanUserCount() - 1))) && e.getPlanStatus() == TaskStatusEnum.BY_FINISH.getStatus()).map(ElevatorPlanUserDTO::getPlanId).distinct().count());
		}
		return resultMap;
	}

	@Override
	public List<MaintainPlanContent> screenUserPlanStatisticsList(List<Long> userIds) {
		return baseMapper.screenUserPlanStatisticsList(userIds);
	}

}
